Browse Source

- Ajout du download et du share
- Ajout des themes

idleman 4 years ago
parent
commit
e447469160

+ 0 - 2
header.php

@@ -71,8 +71,6 @@ if(!isset($_['admin_login']) && file_exists('enabled.maintenance') && !$myUser->
 		<link href="https://fonts.googleapis.com/css?family=Lato:300,400" rel="stylesheet">
 		<!-- Custom styles for this template -->
 		<link href="<?php echo $mediaRoot ?>/css/main.css?v=<?php echo $cacheVersion; ?>" rel="stylesheet">
-		<!-- Décommenter la ligne d'après pour override le thème général -->
-		<link href="css/theme.css" rel="stylesheet">
 		<!-- Plugin css files -->
 		<?php echo Plugin::callCss($mediaRoot,$cacheVersion); ?>
 	</head>

+ 6 - 2
install.php

@@ -138,9 +138,13 @@ try {
 				$right->save();
 			}
 			//Activation des plugins par défaut
-			foreach (array('fr.idleman.hackpoint','fr.idleman.wiki','fr.idleman.dashboard','fr.idleman.notification') as  $plugin) {
+			foreach (array('fr.idleman.hackpoint','fr.idleman.wiki','fr.idleman.dashboard','fr.idleman.notification','fr.idleman.customiser') as  $plugin) {
 				Plugin::state($plugin,true);
-			} ?>
+			} 
+
+			$conf->put('core_theme','/plugin/customiser/theme/hackpoint/main.css');
+
+			?>
 
 			<div class="alert alert-success alert-dismissable mt-3">
 				<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>

+ 20 - 3
js/plugins.js

@@ -152,9 +152,9 @@
 						$.message('error','Erreur indefinie, merci de contacter un administrateur',0);
 				}
 			},
-			xhr: function()
-			{
+			xhr: function() {
 				var xhr = new window.XMLHttpRequest();
+				if(data.downloadResponse) xhr.responseType = 'blob';
 				xhr.upload.addEventListener("progress", function(evt){
 					if (evt.lengthComputable) {
 					var percentComplete = (evt.loaded / evt.total) * 100;
@@ -169,6 +169,23 @@
 					if(progress) progress(percentComplete,'download');
 					}
 				}, false);
+				xhr.addEventListener('readystatechange', function(e) {
+					if(xhr.readyState == 4  && xhr.status == 200) {
+						if(data.downloadResponse){
+							var disposition = xhr.getResponseHeader('content-disposition');
+							var matches = /"([^"]*)"/.exec(disposition);
+	        				var filename = (matches != null && matches[1] ? matches[1] : 'file');
+					        var blob = new Blob([xhr.response], { type: xhr.response.type });
+					        var link = document.createElement('a');
+					        link.href = window.URL.createObjectURL(blob);
+					        link.download = filename;
+					        $('body').append(link);
+					        link.click();
+					        link.remove();
+					        window.URL.revokeObjectURL(link);
+				        }
+					}
+				});
 				return xhr;
 			}
 		};
@@ -521,7 +538,7 @@ $.fn.extend({
 					container.append(line);
 
 					if(option.showItems){
-						line.removeClass('hidden').removeClass('hide');
+						line.removeClass('hidden').removeClass('hide').removeClass('noDisplay');
 					}
 					
 

+ 6 - 23
plugin/customiser/action.php

@@ -9,33 +9,16 @@ switch($_['action']){
 			unlink(__DIR__.SLASH.'css'.SLASH.'theme.css');
 		header('location: setting.php?section=global.customiser');
 	break;
-	
-	//Sauvegarde des configurations de customiser
-	case 'customiser_setting_save':
+
+	case 'customiser_theme_save':
 		Action::write(function(&$response){
 			global $myUser,$_,$conf;
 			if(!$myUser->can('customiser','configure')) throw new Exception("Permissions insuffisantes",403);
-
-			$themePath = __DIR__.SLASH.'css'.SLASH.'theme.css';
-			if(!file_exists($themePath)) exit('Feuille de thème manquante');
-			$themeStream = file_get_contents($themePath);
-
-			foreach ($_['fields'] as $i=>$field) {
-				if($field['type']=='image'){
-					if(!isset($_FILES['fields']) || !isset($_FILES['fields']['name'][$i])) continue;
-					$filename = time().$_FILES['fields']['name'][$i]['value'];
-					copy($_FILES['fields']['tmp_name'][$i]['value'],__DIR__.SLASH.'img'.SLASH.$filename);
-					$value = "url('../img/$filename')";
-				}
-				if(isset($field['value']) && !empty($field['value'])) 
-					$value = $field['value'];
-				
-				$themeStream = preg_replace('$(\n'.preg_quote($field['signature']).'[\s\t\r\n]*?\s?\{.*'.$field['instruction'].': )([^;]*)(;.*})$isU','${1}'.$value.'$3', $themeStream );
-			}
-			file_put_contents(__DIR__.SLASH.'css'.SLASH.'theme.css',$themeStream);
-
-
+			
+			$conf->put('core_theme',$_['theme']);
+		
 		});
 	break;
+
 }
 ?>

+ 4 - 4
plugin/customiser/app.json

@@ -1,12 +1,12 @@
 {
-	"id": "fr.idleman.customiser",
+	"id": "fr.sys1.customiser",
 	"name": "Customiser",
 	"author" : {
-		"name" : "Idleman",
-		"mail" : "developpement@idleman.fr"
+		"name" : "Administrateur SYS1",
+		"mail" : "developpement@sys1.fr"
 	},
 	"version": "1.0",
-	"url": "http://idleman.fr",
+	"url": "http://sys1.fr",
 	"licence": {"name": "Copyright","url" : ""},
 	"description": "Plugin de personnalisation rapide du thème",
 	"require" : {}

+ 35 - 8
plugin/customiser/css/main.css

@@ -5,15 +5,42 @@
 	
 }
 
-#customisers {
-
+.customiser .theme-cards {
+	list-style-type: none;
+	margin:0;
+	padding:0;
 }
-
-/* formulaire d'édition de  */
-.customiser .-form {
-	
+.customiser .theme-cards > li {
+	display: inline-block;
+	vertical-align: top;
+	margin:0;
+    width: 33%;
+	padding:15px;
+	transition: transform 0.2s ease-in-out;
+}
+.customiser .theme-cards > li:hover {
+	transform: scale(1.1);
+}
+.customiser .theme-card > label {
+	cursor: pointer;
 }
 
-#-form {
-
+.customiser .theme-card {
+    position: relative;
+    width: 100%;
+    cursor: pointer;
+    display: block;
+    -webkit-transition: all .2s ease-out;
+    transition: all .2s ease-out;
+    height: 0;
+    padding-bottom: 74.5%;
+    background-color: #E5E9EF;
+    border-radius: 8px;
+    -webkit-box-shadow: 0 25px 20px -20px rgba(0, 0, 0, 0.3), 0 0 15px rgba(0, 0, 0, 0.06);
+    box-shadow: 0 25px 20px -20px rgba(0, 0, 0, 0.3), 0 0 15px rgba(0, 0, 0, 0.06);
+    -webkit-transition: all .5s ease-out;
+}
+.customiser .theme-card  img {
+    border-radius: 8px;
+    max-width: 100%;
 }

+ 0 - 134
plugin/customiser/css/theme.sample.css

@@ -1,134 +0,0 @@
-/*::Corps de l'application*/
-body {
-    font-family: 'Lato', sans-serif;
-    font-size: 1rem;
-    color: #212529;
-    background-color: #fff;
-}
-
-/*:: Logo */
-#mainMenu .navbar-brand {
-    background-image: url(../../../img/logo/logo.png);
-}
-
-/*::Barre de menu en haut de page*/
-.navbar-dark .navbar-nav .nav-link {
-    color: rgba(255,255,255,.5);
-}
-
-/*::Barre de menu en haut de page*/
-#mainMenu {
-    background-color: #373b3c;
-}
-/*::Listes*/
-.list-group-item {
-    background-color: #fff;
-    border: 1px solid rgba(0,0,0,.125);
-}
-/*::Listes actives*/
-.list-group-item.active {
-    color: #fff;
-    background-color: #007bff;
-    border-color: #007bff;
-}
-/*::Tableaux - ligne paires */
-.table-striped tbody tr:nth-of-type(odd) {
-    background-color: #ffffff;
-}
-/*::Tableaux - ligne impaires */
-.table-striped tbody tr:nth-of-type(even) {
-    background-color: rgba(0,0,0,.05);
-}
-/*::Bouton succès*/
-.btn-success {
-	color: #fff;
-    background-color: #28a745;
-    border-color: #28a745;
-}
-/*::Bouton succès au survol*/
-.btn-success:hover,
-.btn-success:focus,
-.btn-success:active,
-.btn-success:not(:disabled):not(.disabled).active,
-.btn-success:not(:disabled):not(.disabled):active,
-.show > .btn-success.dropdown-toggle {
-	color: #fff;
-    background-color: #218838;
-    border-color: #1e7e34;
-}
-/*::Bouton standard*/
-.btn-primary {
-	color: #fff;
-    background-color: #007bff;
-    border-color: #007bff;
-}
-/*::Bouton standard au survol*/
-.btn-primary:hover,
-.btn-primary:focus,
-.btn-primary:active,
-.btn-primary:not(:disabled):not(.disabled).active,
-.btn-primary:not(:disabled):not(.disabled):active,
-.show > .btn-primary.dropdown-toggle {
-	color: #fff;
-    background-color: #0069d9;
-    border-color: #0062cc;
-}
-/*::Boutton info*/
-.btn-info {
-	color: #fff;
-    background-color: #17a2b8;
-    border-color: #17a2b8;
-}
-/*::Boutton info au survol*/
-.btn-info:hover,
-.btn-info:focus,
-.btn-info:active,
-.btn-info:not(:disabled):not(.disabled).active,
-.btn-info:not(:disabled):not(.disabled):active,
-.show > .btn-info.dropdown-toggle {
-	color: #fff;
-    background-color: #138496;
-    border-color: #117a8b;
-}
-/*::Boutton danger*/
-.btn-danger {
-
-		color: #fff;
-    background-color: #dc3545;
-    border-color: #dc3545;
-	
-}
-/*::Boutton danger au survol*/
-.btn-danger:hover,
-.btn-danger:focus,
-.btn-danger:active,
-.btn-danger:not(:disabled):not(.disabled).active,
-.btn-danger:not(:disabled):not(.disabled):active,
-.show > .btn-danger.dropdown-toggle {
-	color: #fff;
-    background-color: #c82333;
-    border-color: #bd2130;
-}
-/*::Boutton sombres*/
-.btn-dark {
-    color: #fff;
-    background-color: #343a40;
-    border-color: #343a40;
-}
-
-
-/*::Lien */
-a {
-    color: #007bff;
-}
-/*::Lien au survol*/
-a:hover {
-    color: #0056b3;
-}
-
-/*::Pied de page*/
-.footer { 
-    background-color: #f5f5f5;
-}
-
-

+ 6 - 7
plugin/customiser/customiser.plugin.php

@@ -1,24 +1,19 @@
 <?php
 //Fonction executée lors de l'activation du plugin
 function customiser_install($id){
-	if($id != 'fr.idleman.customiser') return;
+	if($id != 'fr.sys1.customiser') return;
 	Entity::install(__DIR__);
-	copy(__DIR__.SLASH.'css'.SLASH.'theme.sample.css',__DIR__.SLASH.'css'.SLASH.'theme.css');
-
 }
 
 //Fonction executée lors de la désactivation du plugin
 function customiser_uninstall($id){
-	if($id != 'fr.idleman.customiser') return;
+	if($id != 'fr.sys1.customiser') return;
 	Entity::uninstall(__DIR__);
-	if(file_exists(__DIR__.SLASH.'css'.SLASH.'theme.css'))
-	unlink(__DIR__.SLASH.'css'.SLASH.'theme.css');
 }
 
 //Déclaration des sections de droits du plugin
 function customiser_section(&$sections){
 	$sections['customiser'] = "Gestion des droits sur le plugin customiser";
-	// $sections[''] = "Gestion des droits sur l'entité ";
 }
 
 //Cette fonction comprends toutes les actions 
@@ -47,7 +42,11 @@ function customiser_content_setting(){
 		require_once(__DIR__.SLASH.'setting.'.$_['section'].'.php');
 }
 
+global $conf;
+if(!empty($conf->get('core_theme'))){
 
+	Plugin::addCss(str_replace('plugin/customiser','',$conf->get('core_theme')),true); 
+}
 //Déclation des assets
 if(file_exists(__DIR__.SLASH.'css'.SLASH.'theme.css'))
 Plugin::addCss("/css/theme.css?v=".filemtime(__DIR__.SLASH.'css'.SLASH.'theme.css')); 

BIN
plugin/customiser/img/default-cover.jpg


+ 8 - 38
plugin/customiser/js/main.js

@@ -6,48 +6,18 @@ function init_plugin_customiser(){
 	}
 }
 
+function customiser_preview(element){
+	var css = $(element).attr('data-css');
+	$('#customiser-preview').remove();
+	if(css!='') $('head').append('<link rel="stylesheet" id="customiser-preview" type="text/css" href="'+css+'">');
+}
 
-//Enregistrement des configurations
-function customiser_setting_save(){
-	var fields = [];
-	$('input,select','#customiser-setting-form').each(function(i,element){
-		element = $(element);
-		var value = element.val();
-		if(element.attr('type') == 'file'){
-			value = element[0].files[0];
-		}
-		fields.push({
-			signature : element.attr('data-signature'),
-			instruction : element.attr('data-instruction'),
-			value : value,
-			type : element.attr('data-field-type'),
-			id : element.attr('id')
-		});
-	});
+function customiser_theme_save(){
 
 	$.action({ 
-		action : 'customiser_setting_save', 
-		fields :  fields 
+		action : 'customiser_theme_save', 
+		theme :  $('[name="selected-theme"]:checked').val() 
 	},function(){
 		$.message('success','Enregistré');
 	});
-}
-
-
-function customiser_preview(element){
-	element = $(element);
-	var value =  element.val();
-	if(element.attr('data-field-type')=='image'){
-		
-		var reader = new FileReader();
-    	reader.onload = function (e) {
-    		$(element.attr('data-signature')).css(element.attr('data-instruction'),'url('+e.target.result+')');
-    	}
-    	reader.readAsDataURL(element[0].files[0]);
-	}else{
-		$(element.attr('data-signature')).css(element.attr('data-instruction'),value);
-		console.log(element.attr('data-signature'),element.attr('data-instruction'),value);
-	}
-
-	
 }

+ 129 - 0
plugin/customiser/setting.customize.customiser.php

@@ -0,0 +1,129 @@
+<?php 
+<?php
+global $myUser,$conf;
+if(!$myUser->can('customiser','configure')) throw new Exception("Vous n'avez pas la permission pour executer cette fonctionnalité",403);
+
+$themePath = __DIR__.SLASH.'css'.SLASH.'theme.css';
+if(!file_exists($themePath)) 
+	copy(__DIR__.SLASH.'css'.SLASH.'theme.sample.css',__DIR__.SLASH.'css'.SLASH.'theme.css');
+
+$themeStream = file_get_contents($themePath);
+
+$types = array(
+	'background-color' => array('label'=>'Couleur de fond','type'=>'color'),
+	'border-color' => array('label'=>'Couleur de bordure','type'=>'color'),
+	'background-image'=>array('label'=>'Image de fond','type'=>'image'),
+	'color'=>array('label'=>'Couleur de texte','type'=>'color'),
+	'font-size'=>array('label'=>'Taille de texte','type'=>'size'),
+	'font-family'=>array('label'=>'Police','type'=>'font'),
+);
+
+preg_match_all('$/\*::([^\*]*)\*/
+[\n\r\s\t]*([#.]?[^\{]*){([^\}]*)
+}$iUs', $themeStream , $matches,PREG_SET_ORDER);
+
+$css = array();
+foreach ($matches as $match) {
+	preg_match_all('$(.*):(.*);$iU', $match[3] , $contentMatches,PREG_SET_ORDER);
+	$properties = array();
+	foreach($contentMatches as $contentMatch){
+		$property = array(
+			'instruction' => trim($contentMatch[1]),
+			'value' => trim($contentMatch[2]),
+		
+			'id' =>  base64_encode($match[2].'-'.trim($contentMatch[1])),
+		);
+
+		if(!isset($types[$property['instruction']])) continue;
+
+		$property['type'] = $types[$property['instruction']]['type'];
+		$property['description'] = $types[$property['instruction']]['label'];
+
+
+		$properties[] = $property;
+	}
+	if(count($properties)==0) continue;
+	if(!isset($css[trim($match[1])])) $css[trim($match[1])] = array();
+	$css[trim($match[1])][] = array(
+		'comment' => trim($match[1]),
+		'signature' =>  trim($match[2]),
+		'content' => $properties
+	);
+}
+?>
+
+<div class="row">
+	<div class="col-md-12">
+		<br>
+		<?php if($myUser->can('customiser', 'edit')) : ?>
+			<div onclick="customiser_setting_save();" class="btn btn-success float-right"><i class="fas fa-check"></i> Enregistrer</div>
+			<div onclick="if(confirm('Cette action est irreverssible, êtes vous sûre de vouloir réinitialiser le thème?'))window.location='action.php?action=customiser_reset_theme';" class="btn btn-danger float-right mr-2"><i class="fas fa-undo-alt"></i> Réinitialiser</div>
+		<?php endif; ?>
+
+
+		
+		<h3>Personnalisation du thème</h3>
+		<div class="clear"></div>
+		<hr>
+	</div>
+</div>
+<div class="row">
+	<!-- search results -->
+	<div class="col-xl-12">
+		<table id="customiser-setting-form" class="table table-striped">
+			<tbody>
+				<?php foreach($css as $comment=>$blocks): ?>
+				<tr>
+					<th colspan="2"><h5><i class="fas fa-angle-right"></i> <?php echo $comment;?></h5></th>
+				</tr>
+				<?php foreach($blocks as $block): ?>
+					<?php foreach($block['content'] as $property): ?>
+					<tr>
+						<th class="align-middle"><?php echo $property['description']; ?></th>
+						<td class="align-middle"><?php 
+						$attributes = array();
+						if(isset($infos['placeholder'])) $attributes[] = 'placeholder="'.$infos['placeholder'].'"';
+						$attributes['class'] = 'class="form-control"';
+						$attributes[] = 'id="'.$property['id'].'"';
+						$attributes[] = 'data-signature="'.$block['signature'].'"';
+						$attributes[] = 'data-instruction="'.$property['instruction'].'"';
+						$attributes[] = 'data-field-type="'.$property['type'].'"';
+						$attributes['value'] = 'value="'.$property['value'].'"';
+						$attributes['change'] = 'onchange="customiser_preview(this);"';
+						switch($property['type']){
+							case 'color':
+							if(strlen($property['value']) == 4){
+								$property['value']  = '#'.str_repeat(substr($property['value'],1), 2);
+								$attributes['value'] = 'value="'.$property['value'].'"';
+							}
+							$input = '<input type="color" '.implode(' ',$attributes).'  >'; 
+							break;
+							case 'image':
+								$property['value'] = str_replace(array("url","'",'"',"(",")"),'',$property['value']);
+								$property['value'] = str_replace(array("../"),'',$property['value']);
+								$attributes['value'] = 'value="'.$property['value'].'"';
+								//$attributes['data-type'] = 'data-type="image"';
+								$input = '<input type="file" '.implode(' ',$attributes).'  >'; 
+							break;
+							case 'font':
+								$property['value'] = str_replace(array("'",'"'),'',$property['value']);
+								$attributes['value'] = 'value="'.$property['value'].'"';
+								$input = '<input type="text" '.implode(' ',$attributes).'  >'; 
+							break;
+							default:
+								$input = '<input type="text" '.implode(' ',$attributes).'  >'; 
+							break;
+						}
+						echo $input; ?>
+						</td>
+					<?php endforeach; ?>
+				<?php endforeach; ?>
+				</tr>
+				<?php endforeach; ?>
+			</tbody>
+		</table>
+	</div>
+</div>
+
+
+?>

+ 46 - 102
plugin/customiser/setting.global.customiser.php

@@ -2,121 +2,65 @@
 global $myUser,$conf;
 if(!$myUser->can('customiser','configure')) throw new Exception("Vous n'avez pas la permission pour executer cette fonctionnalité",403);
 
-$themePath = __DIR__.SLASH.'css'.SLASH.'theme.css';
-if(!file_exists($themePath)) 
-	copy(__DIR__.SLASH.'css'.SLASH.'theme.sample.css',__DIR__.SLASH.'css'.SLASH.'theme.css');
+$themes = array(
 
-$themeStream = file_get_contents($themePath);
-
-$types = array(
-	'background-color' => array('label'=>'Couleur de fond','type'=>'color'),
-	'border-color' => array('label'=>'Couleur de bordure','type'=>'color'),
-	'background-image'=>array('label'=>'Image de fond','type'=>'image'),
-	'color'=>array('label'=>'Couleur de texte','type'=>'color'),
-	'font-size'=>array('label'=>'Taille de texte','type'=>'size'),
-	'font-family'=>array('label'=>'Police','type'=>'font'),
+	"default" => array(
+		"label" => "Défaut",
+		"folder" => "",
+		"css-relative-url" => "",
+		"path" => "",
+		"checked" => $conf->get('core_theme') == "",
+		"last-update" => 0
+	)
 );
 
-preg_match_all('$/\*::([^\*]*)\*/
-[\n\r\s\t]*([#.]?[^\{]*){([^\}]*)
-}$iUs', $themeStream , $matches,PREG_SET_ORDER);
-
-$css = array();
-foreach ($matches as $match) {
-	preg_match_all('$(.*):(.*);$iU', $match[3] , $contentMatches,PREG_SET_ORDER);
-	$properties = array();
-	foreach($contentMatches as $contentMatch){
-		$property = array(
-			'instruction' => trim($contentMatch[1]),
-			'value' => trim($contentMatch[2]),
-		
-			'id' =>  base64_encode($match[2].'-'.trim($contentMatch[1])),
-		);
-
-		if(!isset($types[$property['instruction']])) continue;
+foreach(glob(__DIR__.SLASH.'theme'.SLASH.'*'.SLASH.'app.json') as $themeFile){
+	$path = dirname($themeFile);
+	$theme = json_decode(file_get_contents($themeFile),true);
+	$theme['folder'] = $path;
 
-		$property['type'] = $types[$property['instruction']]['type'];
-		$property['description'] = $types[$property['instruction']]['label'];
+	$theme['css-relative-url'] = '/plugin/customiser/theme/'.basename($path).'/main.css';
+	$theme['checked'] = $conf->get('core_theme') == $theme['css-relative-url'];
+	$theme['last-update'] = filemtime($themeFile);
+	$themes[] = $theme;
+}
 
 
-		$properties[] = $property;
-	}
-	if(count($properties)==0) continue;
-	if(!isset($css[trim($match[1])])) $css[trim($match[1])] = array();
-	$css[trim($match[1])][] = array(
-		'comment' => trim($match[1]),
-		'signature' =>  trim($match[2]),
-		'content' => $properties
-	);
-}
 ?>
 
-<div class="row">
+<div class="row customiser">
 	<div class="col-md-12">
 		<br>
 		<?php if($myUser->can('customiser', 'edit')) : ?>
-			<div onclick="customiser_setting_save();" class="btn btn-success float-right"><i class="fas fa-check"></i> Enregistrer</div>
-			<div onclick="if(confirm('Cette action est irreverssible, êtes vous sûre de vouloir réinitialiser le thème?'))window.location='action.php?action=customiser_reset_theme';" class="btn btn-danger float-right mr-2"><i class="fas fa-undo-alt"></i> Réinitialiser</div>
+			<div onclick="customiser_theme_save();" class="btn btn-success float-right"><i class="fas fa-check"></i> Enregistrer</div>
+			
 		<?php endif; ?>
-		<h3>Réglages Thème</h3>
-		<div class="clear"></div>
+
+		<h3>Choix du Thème</h3>
 		<hr>
-	</div>
-</div>
-<div class="row">
-	<!-- search results -->
-	<div class="col-xl-12">
-		<table id="customiser-setting-form" class="table table-striped">
-			<tbody>
-				<?php foreach($css as $comment=>$blocks): ?>
-				<tr>
-					<th colspan="2"><h5><i class="fas fa-angle-right"></i> <?php echo $comment;?></h5></th>
-				</tr>
-				<?php foreach($blocks as $block): ?>
-					<?php foreach($block['content'] as $property): ?>
-					<tr>
-						<th class="align-middle"><?php echo $property['description']; ?></th>
-						<td class="align-middle"><?php 
-						$attributes = array();
-						if(isset($infos['placeholder'])) $attributes[] = 'placeholder="'.$infos['placeholder'].'"';
-						$attributes['class'] = 'class="form-control"';
-						$attributes[] = 'id="'.$property['id'].'"';
-						$attributes[] = 'data-signature="'.$block['signature'].'"';
-						$attributes[] = 'data-instruction="'.$property['instruction'].'"';
-						$attributes[] = 'data-field-type="'.$property['type'].'"';
-						$attributes['value'] = 'value="'.$property['value'].'"';
-						$attributes['change'] = 'onchange="customiser_preview(this);"';
-						switch($property['type']){
-							case 'color':
-							if(strlen($property['value']) == 4){
-								$property['value']  = '#'.str_repeat(substr($property['value'],1), 2);
-								$attributes['value'] = 'value="'.$property['value'].'"';
-							}
-							$input = '<input type="color" '.implode(' ',$attributes).'  >'; 
-							break;
-							case 'image':
-								$property['value'] = str_replace(array("url","'",'"',"(",")"),'',$property['value']);
-								$property['value'] = str_replace(array("../"),'',$property['value']);
-								$attributes['value'] = 'value="'.$property['value'].'"';
-								//$attributes['data-type'] = 'data-type="image"';
-								$input = '<input type="file" '.implode(' ',$attributes).'  >'; 
-							break;
-							case 'font':
-								$property['value'] = str_replace(array("'",'"'),'',$property['value']);
-								$attributes['value'] = 'value="'.$property['value'].'"';
-								$input = '<input type="text" '.implode(' ',$attributes).'  >'; 
-							break;
-							default:
-								$input = '<input type="text" '.implode(' ',$attributes).'  >'; 
-							break;
-						}
-						echo $input; ?>
-						</td>
-					<?php endforeach; ?>
-				<?php endforeach; ?>
-				</tr>
+		<div class="row">
+			<ul class="theme-cards">
+				<?php foreach($themes as $theme): 
+
+					$cover = ROOT_URL.'/plugin/customiser/';
+					if(isset($theme['cover'])){
+						$cover .= 'theme/'.basename($theme['folder']).'/'. $theme['cover'];
+					}else{
+						$cover .= 'img/default-cover.jpg';
+					}
+					?>
+				<li >
+					<div class="theme-card"  data-css="<?php echo ROOT_URL.$theme['css-relative-url']; ?>" onclick="customiser_preview(this);">
+						<label>
+							<img src="<?php echo $cover; ?>">
+							<h5 class="mb-2 mt-2"><input type="radio" data-type="radio" <?php echo $theme['checked']?"checked='checked'":""; ?> value="<?php echo $theme['css-relative-url']; ?>" name="selected-theme"> <?php echo $theme['label']; ?></h5>
+							<span class="text-muted"><i class="far fa-meh-blank"></i> <?php echo isset($theme['author']) ? $theme['author']['name'] : 'Auteur inconnu'; ?> - <i class="far fa-calendar-alt"></i> <?php echo relative_time($theme['last-update']); ?></span>
+						</label>
+					</div>
+				</li>
 				<?php endforeach; ?>
-			</tbody>
-		</table>
+			</ul>
+		</div>
 	</div>
 </div>
+

+ 9 - 0
plugin/customiser/theme/example/app.json

@@ -0,0 +1,9 @@
+{
+	"id": "fr.sys1.theme.example",
+	"label": "Example",
+	"cover": "cover.jpg",
+	"author" : {
+		"name" : "Administrateur SYS1",
+		"mail" : "developpement@sys1.fr"
+	}
+}

BIN
plugin/customiser/theme/example/cover.jpg


+ 589 - 0
plugin/customiser/theme/example/main.css

@@ -0,0 +1,589 @@
+/* OVERRIDE - À MODIFIER POUR CHANGER LE THÈME GÉNÉRAL */
+/*Sélection avec la souris*/
+::selection {
+    color: #fff;
+    background: #993352; /* WebKit/Blink Browsers */
+}
+::-moz-selection {
+    color: #fff;
+    background: #993352; /* Gecko Browsers */
+}
+/* Toast Javascript pour les messages renvoyés */
+.toast-error {
+    background: #ca023e !important;
+}
+.toast-info {
+    background: #9d948b !important;
+}
+.toast-success {
+    background: #1e998d !important;
+}
+.toast-warning {
+    color: #212529 !important;
+    background: #cea75d !important;
+}
+
+.update-timeline-badge.primary { background-color: #847a71 !important; }
+.update-timeline-badge.success { background-color: #1e998d !important; }
+.update-timeline-badge.warning { background-color: #cea75d !important; }
+.update-timeline-badge.danger { background-color: #ca023e !important; }
+.update-timeline-badge.info { background-color: #9c948b !important; }
+
+/* Textes bootstrap */
+.text-info { color: #9c948b!important; }
+.text-success { color: #1e998d!important; }
+.text-danger { color: #ca023e!important; }
+.text-dark { color: #373b3c!important; }
+.text-primary { color: #847a71!important; }
+/*.text-warning { color: #28a745!important; }
+.text-light { color: #28a745!important; }
+.text-secondary { color: #28a745!important; }*/
+
+.btn .text-info:hover,
+.btn .text-info:focus {
+    color: #847a71!important;
+    transition: color .1s ease-in-out;
+}
+.btn .text-success:hover,
+.btn .text-success:focus {
+    color: #166f66!important;
+    transition: color .1s ease-in-out;
+}
+.btn .text-danger:hover,
+.btn .text-danger:focus {
+    color: #97022f!important;
+    transition: color .1s ease-in-out;
+}
+.btn .text-dark:hover,
+.btn .text-dark:focus {
+    color: #202222!important;
+    transition: color .1s ease-in-out;
+}
+.btn .text-primary:hover,
+.btn .text-primary:focus {
+    color: #4d4742!important;
+    transition: color .1s ease-in-out;
+}
+
+
+/*Bouton de retour en haut*/
+#toTheTop{
+    background-color: #8d1136;
+}
+#toTheTop:after{
+    color: #fff;
+}
+/*Barre de menu en haut de page*/
+#mainMenu {
+    border-top: 3px solid #8d1136;
+    background: #373b3c;
+}
+/* Liens navbar*/
+.nav-pills .nav-link.active,
+.nav-pills .show > .nav-link {
+    background-color: #1e998d;
+}
+.navbar-nav .nav-link {
+    padding-right: 1rem !important; 
+    padding-left: 1rem !important; 
+}
+.navbar-dark .navbar-nav .nav-link,
+.navbar-dark .navbar-nav .nav-link {
+    color: #9c9c9c;
+}
+.navbar-dark .navbar-nav .active > .nav-link,
+.navbar-dark .navbar-nav .nav-link.active,
+.navbar-dark .navbar-nav .nav-link.show,
+.navbar-dark .navbar-nav .show > .nav-link {
+    color: #ffffff;
+}
+.navbar-dark .navbar-nav .nav-link:focus,
+.navbar-dark .navbar-nav .nav-link:hover {
+    color: #ffffff;
+    transition: all .1s ease-out;
+}
+/* Inputs */
+input:required,
+textarea:required,
+select:required {
+    border-left: 0.25rem solid #993352 !important;
+}
+
+/*Boutons & Badges*/
+.btn-success {
+    background-color: #1e998d;
+    border-color: #1e998d;
+}
+.btn-success:hover,
+.btn-success:focus,
+.btn-success:active,
+.btn-success:not(:disabled):not(.disabled).active,
+.btn-success:not(:disabled):not(.disabled):active,
+.show > .btn-success.dropdown-toggle {
+    box-shadow: none !important;
+    background-color: #166f66;
+    border-color: #166f66;
+}
+.btn-success:not(:disabled):not(.disabled).active:focus,
+.btn-success:not(:disabled):not(.disabled):active:focus,
+.show > .btn-success.dropdown-toggle:focus {
+    box-shadow: none;
+}
+.btn-success.disabled,
+.btn-success:disabled {
+    color: #fff;
+    background-color: #1e998d;
+    border-color: #1e998d;
+}
+.badge-success {
+    color: #fff;
+    background-color: #1e998d;
+}
+.badge-success[href]:focus,
+.badge-success[href]:hover {
+    background-color: #166f66;
+}
+.border-success {
+    border-color: #1e998d !important;
+}
+.btn-primary {
+    background-color: #ffffff;
+    border-color: #847a71;
+    color: #847a71;
+}
+.btn-primary:hover,
+.btn-primary:focus,
+.btn-primary:active,
+.btn-primary:not(:disabled):not(.disabled).active,
+.btn-primary:not(:disabled):not(.disabled):active,
+.show > .btn-primary.dropdown-toggle {
+    box-shadow: none;
+    background-color: #e3e0de;
+    border-color: #4d4742;
+    color: #4d4742;
+}
+.btn-primary:not(:disabled):not(.disabled).active:focus,
+.btn-primary:not(:disabled):not(.disabled):active:focus,
+.show > .btn-primary.dropdown-toggle:focus {
+    box-shadow: none;
+}
+.btn-primary.disabled,
+.btn-primary:disabled {
+    color: #fff;
+    background-color: #847a71;
+    border-color: #847a71;
+}
+.badge-primary {
+    color: #847a71;
+    border: 1px solid;
+    border-color: #847a71;
+    background-color: #ffffff;
+}
+.badge-primary[href]:focus,
+.badge-primary[href]:hover {
+    color: #4d4742;
+    border-color: #4d4742;
+    background-color: #e3e0de;
+}
+.border-primary {
+    border-color: #847a71 !important;
+}
+.btn-dark {
+    color: #ffffff;
+    background-color: #373b3c;
+    border-color: #373b3c;
+}
+.btn-dark:hover,
+.btn-dark:focus,
+.btn-dark:active,
+.btn-dark:not(:disabled):not(.disabled).active,
+.btn-dark:not(:disabled):not(.disabled):active,
+.show > .btn-dark.dropdown-toggle {
+    box-shadow: none;
+    background-color: #202222;
+    border-color: #202222;
+}
+.btn-dark:not(:disabled):not(.disabled).active:focus,
+.btn-dark:not(:disabled):not(.disabled):active:focus,
+.show > .btn-dark.dropdown-toggle:focus {
+    box-shadow: none;
+}
+.btn-dark.disabled,
+.btn-dark:disabled {
+    color: #ffffff;
+    background-color: #373b3c;
+    border-color: #373b3c;
+}
+.badge-dark {
+    color: #ffffff;
+    background-color: #373b3c;
+}
+.badge-dark[href]:focus,
+.badge-dark[href]:hover {
+    background-color: #202222;
+}
+.border-dark {
+    border-color: #373b3c !important;
+}
+.btn-info {
+    background-color: #9c948b;
+    border-color: #9c948b;
+}
+.btn-info:hover,
+.btn-info:focus,
+.btn-info:active,
+.btn-info:not(:disabled):not(.disabled).active,
+.btn-info:not(:disabled):not(.disabled):active,
+.show > .btn-info.dropdown-toggle {
+    box-shadow: none;
+    background-color: #847a71;
+    border-color: #847a71;
+}
+.btn-info:not(:disabled):not(.disabled).active:focus,
+.btn-info:not(:disabled):not(.disabled):active:focus,
+.show > .btn-info.dropdown-toggle:focus {
+    box-shadow: none;
+}
+.btn-info.disabled,
+.btn-info:disabled {
+    color: #fff;
+    background-color: #9c948b;
+    border-color: #9c948b;
+}
+.badge-info {
+    color: #fff;
+    background-color: #847a71;
+}
+.badge-info[href]:focus,
+.badge-info[href]:hover {
+    background-color: #847a71;
+}
+.border-info {
+    border-color: #9c948b !important;
+}
+.btn-danger {
+    background-color: #ca023e;
+    border-color: #ca023e;
+}
+.btn-danger:hover,
+.btn-danger:focus,
+.btn-danger:active,
+.btn-danger:not(:disabled):not(.disabled).active,
+.btn-danger:not(:disabled):not(.disabled):active,
+.show > .btn-danger.dropdown-toggle {
+    box-shadow: none;
+    background-color: #97022f;
+    border-color: #97022f;
+}
+.btn-danger:not(:disabled):not(.disabled).active:focus,
+.btn-danger:not(:disabled):not(.disabled):active:focus,
+.show > .btn-danger.dropdown-toggle:focus {
+    box-shadow: none;
+}
+.btn-danger.disabled,
+.btn-danger:disabled {
+    color: #fff;
+    background-color: #ca023e;
+    border-color: #ca023e;
+}
+.badge-danger {
+    color: #fff;
+    background-color: #ca023e;
+}
+.badge-danger[href]:focus,
+.badge-danger[href]:hover {
+    background-color: #97022f;
+}
+.border-danger {
+    border-color: #ca023e !important;
+}
+.btn-warning {
+    background-color: #cea75d;
+    border-color: #cea75d;
+    color: #212529;
+}
+.btn-warning:hover,
+.btn-warning:focus,
+.btn-warning:active,
+.btn-warning:not(:disabled):not(.disabled).active,
+.btn-warning:not(:disabled):not(.disabled):active,
+.show > .btn-warning.dropdown-toggle {
+    box-shadow: none !important;
+    background-color: #c09139;
+    border-color: #c09139;
+}
+.btn-warning:not(:disabled):not(.disabled).active:focus,
+.btn-warning:not(:disabled):not(.disabled):active:focus,
+.show > .btn-warning.dropdown-toggle:focus {
+    box-shadow: none;
+}
+.btn-warning.disabled,
+.btn-warning:disabled {
+    color: #fff;
+    background-color: #cea75d;
+    border-color: #cea75d;
+}
+.badge-warning {
+    color: #fff;
+    background-color: #cea75d;
+}
+.badge-warning[href]:focus,
+.badge-warning[href]:hover {
+    background-color: #c09139;
+}
+.border-warning {
+    border-color: #cea75d !important;
+}
+
+/*Dropdown*/
+.dropdown-item.bg-green:focus,
+.dropdown-item.bg-pink:focus,
+.dropdown-item.bg-dark-grey:focus,
+.dropdown-item.bg-light-grey:focus,
+.dropdown-item.bg-bordeaux:focus,
+.dropdown-item.bg-golden:focus,
+.dropdown-item.bg-green:hover,
+.dropdown-item.bg-pink:hover,
+.dropdown-item.bg-dark-grey:hover,
+.dropdown-item.bg-light-grey:hover,
+.dropdown-item.bg-bordeaux:hover,
+.dropdown-item.bg-golden:hover {
+    color: #fff;
+}
+.dropdown-item.active,
+.dropdown-item:active {
+    background-color: #1e998d;
+    color: #fff;
+}
+
+/*Override append input-group*/
+.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle) {
+     border-top-right-radius: 3px; 
+     border-bottom-right-radius: 3px; 
+}
+
+/*Pagination*/
+.page-item.active .page-link {
+    color: #fff;
+    background-color: #9c948b;
+    border-color: #9c948b;
+}
+.page-link {
+    color: #9c948b;
+    background-color: #fff;
+    border: 1px solid #9c948b;
+}
+.page-link:focus, .page-link:hover {
+    color: #847a71;
+    background-color: #e9ecef;
+    border-color: #9c948b;
+}
+
+/*Menus généraux*/
+.list-group-item.active {
+    color: #fff;
+    background-color: #1e998d;
+    border-color: #1e998d;
+}
+a {
+    color: #1e998d;
+}
+a:hover {
+    color: #166f66;
+}
+
+/*Datepicker jQuery UI*/
+/*Pour les icône précédent/suivant il faut changer la couleur ud fichier d'icone de jQuery*/
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year {
+    width: 45%;
+    display: inline-block;
+    padding: 0 .75rem;
+    line-height: 1;
+    height: auto !important;
+}
+.ui-datepicker select.ui-datepicker-month.form-control {
+    margin-right: 5px;
+}
+.ui-datepicker select.ui-datepicker-year.form-control {
+    margin-left: 5px;
+}
+.ui-widget-header {
+    border: none;
+    background: #ffffff; 
+    color: #444;
+    font-weight: bold;
+}
+.ui-datepicker .ui-datepicker-prev {
+    left: 2px;
+    border-radius: 3px;
+    cursor: pointer;
+}
+.ui-datepicker .ui-datepicker-next {
+    right: 2px;
+    border-radius: 3px;
+    cursor: pointer;
+}
+div#ui-datepicker-div {
+    /*z-index: 20 !important;*/
+    background-color: #ffffff;
+    border: 1px solid #ddd;
+    border-radius: .25rem;
+}
+.ui-datepicker th {
+    padding: 0;
+    text-align: center;
+    font-weight: bold;
+    border: 0;
+}
+.ui-datepicker th > span {
+    border-bottom: 1px solid #d8d8d8;
+    color: #5f5f5f;
+    width: 100%;
+    display: block;
+    padding: .7em .3em;
+    padding-bottom: .35em;
+    margin-bottom: 5px;
+}
+.ui-state-default,
+.ui-widget-content .ui-state-default,
+.ui-widget-header .ui-state-default {
+    margin: .15rem 0;
+    border: 1px solid #eaeaea;
+    background: #ffffff;
+    font-weight: normal; 
+    color: #1e998d;
+    font-size: 0.9em;
+    text-align: center;
+    width: 35px;
+    height: 35px;
+    vertical-align: middle;
+    border-radius: 5px;
+    padding-top: 7px;
+}
+.ui-state-highlight,
+.ui-widget-content .ui-state-highlight,
+.ui-widget-header .ui-state-highlight {
+    border: 1px solid #ccc;
+    background: #fff;
+    color: #444;
+}
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active {
+    border: 1px solid #ddd;
+    font-weight: bold;
+    color: #ca023e;
+    background: #ca023a36;
+}
+.ui-state-hover,
+.ui-widget-content .ui-state-hover,
+.ui-widget-header .ui-state-hover,
+.ui-state-focus,
+.ui-widget-content .ui-state-focus,
+.ui-widget-header .ui-state-focus {
+    border: 1px solid #97022f;
+    background: #97022f;
+     font-weight: normal; 
+    color: #fff;
+}
+
+/* Page de maintenance */
+.maintenance-page,
+.maintenance-page body {
+    font-family: 'Lato';
+    background-color: #34495E;
+    color:#fff;
+}
+.maintenance-page .icon{
+    background-color: #ffffff;
+}
+.maintenance-page .icon i{
+    color:#ca023e;
+}
+.maintenance-page .content-block {
+    background: #ffffff33;
+    border: 1px solid #fff;
+}
+.maintenance-page .admin-access a {
+    color:#E9CA78;
+}
+
+/* COMPOSANTS */
+/* Composant User */
+div.data-type-user > ul > li > div {
+    border-bottom: 1px solid #1e998d;
+}
+/* Composant Image */
+.type-image-bloc .btn-delete-img {
+    color: #ca023e !important;
+}
+
+/* Composant checkbox */
+label.check-component {
+    border: 1px solid #bbbbbb;
+}
+label.check-component input:checked + .box {
+    background-color: #d4f7f3;
+}
+label.check-component input:checked + .box:after {
+    border-color: #1e998d;
+}
+label.check-component input:indeterminate + .box {
+    background-color: #fad6e1;
+}
+label.check-component input:indeterminate + .box:after {
+    border-color: #ca023e;
+}
+
+/* Composant radio */
+.radio-component:checked + label,
+.radio-component:not(:checked) + label
+{
+    color: #666;
+}
+.radio-component:checked + label:before,
+.radio-component:not(:checked) + label:before {
+    border: 1px solid #cccccc;
+}
+.radio-component:checked + label:after,
+.radio-component:not(:checked) + label:after {
+    background: #58b1a7;
+}
+
+/* Composant cards */
+*[data-type="card"].card-component-container {
+    color: #1e998d;
+}
+*[data-type="card"].card-component-container:hover {
+    color: #176e65;
+}
+
+/* Composant icônes */
+.component-icon .dropdown-icon-item:focus,
+.component-icon .dropdown-icon-item:active,
+.component-icon .dropdown-icon-item:hover {
+    color: ##fff;
+    background-color: #1e998d;
+}
+
+
+/* PLUGINS */
+/* Notifications */
+ul.notifications.mid-pane > li.unread {
+    border-left: 5px solid #1e998d;
+}
+.notification_menu .dropdown-item.notification-unread:before {
+    border-left: 3px solid #1e998d;
+}
+.notification_menu .notification-item-options > li.notification-read:hover {
+    color: #9c948b;
+}
+.notification_menu .notification-item-options > li.notification-delete:hover {
+    color: #ca023e;
+}
+.notification_menu.dropdown .all-as-read, 
+.notification_menu.dropdown .see-all-link {
+    color: #1e998d;
+}
+/* FIN OVERRIDE */

+ 9 - 0
plugin/customiser/theme/hackpoint/app.json

@@ -0,0 +1,9 @@
+{
+	"id": "fr.idleman.theme.hackpoint",
+	"label": "Hackpoint",
+	"cover": "cover.png",
+	"author" : {
+		"name" : "idleman",
+		"mail" : "idleman.fr/contact"
+	}
+}

BIN
plugin/customiser/theme/hackpoint/cover.png


+ 0 - 0
css/theme.css → plugin/customiser/theme/hackpoint/main.css


+ 1 - 1
plugin/hackpoint/ResourcePart.class.php

@@ -6,7 +6,7 @@
  * @license copyright
  */
 class ResourcePart extends Entity{
-	public $id,$part,$rescource;
+	public $id,$part,$resource;
 	protected $TABLE_NAME = 'hackpoint_resource_part';
 	public $fields =
 	array(

+ 52 - 1
plugin/hackpoint/Sketch.class.php

@@ -21,16 +21,67 @@ class Sketch extends Entity{
 	public $links = array(
 	);
 
-	public function picture(){
+	public function picture($stream = false){
 		$folder = $this->directory();
 		if(!file_exists($folder)) mkdir($folder,0755,true);
 		$picture = $folder.SLASH.'cover.jpg';
 		if(!file_exists($picture)){
 			copy(__DIR__.SLASH.'img'.SLASH.'default-sketch.jpg',$picture);
 		}
+		if($stream) return file_get_contents($picture);
 		return 'action.php?action=hackpoint_download_file&file='.base64_encode('sketch'.SLASH.$this->id.SLASH.'cover.jpg');
 	}
 
+	public function download(){
+		require_once(__DIR__.SLASH.'ResourceType.class.php');
+		$stream = "Fonctionnalité en cours d'implémentation, désolé :p";
+		$folder = $this->directory();//todo
+		
+		$filename = $this->slug.'-'.time().'.zip';
+		$filepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.$filename;
+		$zip = new ZipArchive;
+		$res = $zip->open($filepath, ZipArchive::CREATE);
+		if ($res === TRUE) {
+
+			$mainReadme = $this->toFile();
+			//ajout du md principal
+			$zip->addFromString($mainReadme['name'], $mainReadme['content']);
+			//ajout de l'image de couverture du sketch
+			$zip->addFromString('cover.jpg', $this->picture(true));
+			
+
+			foreach($this->resources() as $resource){
+				$type = ResourceType::types($resource->type);
+				$file = $type['class']::toFile($resource);
+
+				$zip->addFromString($file['name'], $file['content']);
+			}
+			$zip->close();
+		}
+		$stream = file_get_contents($filepath);
+		unlink($filepath);
+		return $stream;
+	}
+
+
+	//Export vers un fichier brut
+	public function toFile(){
+		$content = '# '.$this->label.PHP_EOL.PHP_EOL;
+		$content .= '``'.$this->comment.'``'.PHP_EOL.PHP_EOL;
+		$content .= '* Visibilité : '.($this->state?'Public':'Privé').PHP_EOL;
+		$content .= '* Créé par '.$this->creator.' le '.strtolower(relative_time($this->created)).PHP_EOL;
+		$content .= '* Modifié par '.$this->updater.' le '.strtolower(relative_time($this->updated)).PHP_EOL;
+		return array(
+			'name'=> 'README-SKETCH.md',
+			'content' => html_entity_decode($content)
+		);
+	}
+
+	public function resources(){
+		require_once(__DIR__.SLASH.'Resource.class.php');
+		return Resource::loadAll(array('sketch'=>$this->id));
+	}
+
 	public function directory(){
 		return File::dir().'hackpoint'.SLASH.'sketch'.SLASH.$this->id;
 	}

+ 16 - 0
plugin/hackpoint/action.php

@@ -92,6 +92,22 @@ switch($_['action']){
 		
 	});
 	break;
+
+	case 'hackpoint_sketch_download':
+		Action::write(function(&$response){
+			global $myUser,$_;
+			require_once(__DIR__.SLASH.'Sketch.class.php');
+			if(!is_numeric($_['id'])) throw new Exception("Sketch non spécifié", 400);
+			$sketch = Sketch::provide();
+			if($myUser->login!= $sketch->creator && !$sketch->state) throw new Exception("Permission insuffisantes", 403);
+			
+			
+			File::downloadStream($sketch->download(),$sketch->slug.' '.date('d-m-y H-i-s').'.zip');
+			exit();
+	
+			
+		});
+	break;
 	
 
 	case 'hackpoint_sketch_progress_save':

File diff suppressed because it is too large
+ 5 - 0
plugin/hackpoint/css/animate.min.css


+ 58 - 0
plugin/hackpoint/css/main.css

@@ -24,6 +24,64 @@
     transform: translateY(0px);
 }
 
+textarea.form-control.share-input{
+	color: #b7b7b7;
+    font-size: 11px;
+    font-family: "Consolas", "Verdana";
+    height: 80px;
+}
+
+/* modal*/
+
+.blur{
+	filter: blur(0.3rem);
+}
+
+.modalize-overlay{
+	background-color: rgba(0,0,0,0.7);
+	display: none;
+	width: 100%;
+	height: 100%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	z-index: 10001;
+}
+.modalize{
+	background-color: #192027;
+	display: none;
+	color:#ffffff;
+	padding:15px;
+	width: 700px;
+	height: 500px;
+	position: absolute;
+	border-radius: 3px;
+	top:50%;
+	left:50%;
+	box-shadow: 0 0 10px rgba(0,0,0,0.5);
+	margin-top: -225px; 
+	margin-left: -350px; 
+	z-index: 10002;
+}
+.modalize-header h1{
+	font-weight: 400;
+	padding-bottom: 15px;
+	border-bottom: 1px solid #0f1927;
+	margin-bottom: 15px;
+	color:#91e6ff;
+}
+.modalize-footer{
+	position: absolute;
+	bottom: 10px;
+	right: 10px;
+}
+
+
+
+/**/
+
+
+
 /* Conteneur principal du plugin hackpoint */
 .hackpoint {
 	height: 100%;

+ 1 - 0
plugin/hackpoint/hackpoint.plugin.php

@@ -98,6 +98,7 @@ Plugin::addCss("/css/main.css?v=1");
 Plugin::addCss("/css/codemirror.css?v=1"); 
 Plugin::addCss("/css/codemirror-monokai.css?v=1"); 
 Plugin::addCss("/css/component.css?v=1",true); 
+Plugin::addCss("/css/animate.min.css"); 
 
 Plugin::addJs("/js/main.js?v=1"); 
 Plugin::addJs("/js/codemirror.js?v=1"); 

+ 90 - 1
plugin/hackpoint/js/main.js

@@ -35,10 +35,57 @@ function hackpoint_setting_save(){
 	},function(){ $.message('info','Configuration enregistrée'); });
 }
 
+//plugin jquery pour modale
+$.fn.extend({
+modalize : function(options){
+		var obj = $(this);
+
+		var o = $.extend({
+			blur : null
+		}, options);
+
+		var overlay = $('.modalize-overlay');
+		var modal = $('.modalize');
+		if(overlay.length==0){
+			overlay = $('<div class="modalize-overlay"></div>');
+			modal = $('<div class="modalize bounceIn"></div>');
+			$('body').append(overlay).append(modal);
+		}
+
+		var form = obj.detach();
+		form.removeClass('hide');
+		modal.html(form.get(0).outerHTML);
+    	
+    	var modalize = {
+    		options : o,
+    		modal : modal,
+    		overlay : overlay,
+    		hide : function(){
+    			overlay.fadeOut();
+				$(o.blur).removeClass('blur');
+				modal.hide();
+    		}
+    	}
+
+    	
+    	modal.css('height',o.height?o.height+'px':'');
+
+
+		modal.show();
+		overlay.show();
+		$(o.blur).addClass('blur');
+		overlay.click(function(){
+			modalize.hide();
+		});
+
+		return modalize;
+	}
+});
 
 /** PART **/
 	
 
+
 //Récuperation d'une liste de part dans le tableau #parts
 function hackpoint_resource_part_search(callback){
 	
@@ -288,7 +335,8 @@ function hackpoint_part_delete(element){
 
 
 /** SKETCH **/
-	
+
+
 //Récuperation d'une liste de sketch dans le tableau #sketchs
 function hackpoint_sketch_search(callback){
 	
@@ -353,6 +401,47 @@ function hackpoint_sketch_save(){
 	});
 }
 
+function hackpoint_sketch_download(){
+	var id = $('#sketch-form').attr('data-id');
+
+	$.action({
+			action : 'hackpoint_sketch_download',
+			downloadResponse : true,
+			id : id
+	},function(r){
+		
+	});
+}
+
+function hackpoint_sketch_share(){
+
+	$('#share-sketch-modal').modalize({
+		blur:".hackpoint,#mainMenu",
+		height:300
+	});
+	hackpoint_sketch_share_mode();
+	$('.share-input').click(function () {
+	   $(this).select();
+	});
+	$('.share-menu-mode').click(function () {
+	   hackpoint_sketch_share_mode();
+	});
+}
+
+function hackpoint_sketch_share_mode(){
+	var tpl = $('.shareCode').html();
+
+	var data = {
+		sketch : $('#sketch-form').attr('data-id'),
+		resource : $.urlParam('resource'),
+		menu : $('.share-menu-mode').prop('checked')?1:0,
+		url : window.location.protocol+'//' + window.location.hostname + window.location.pathname
+	}
+	var html = Mustache.render(tpl,data);
+	$('.share-input').html(html);
+}
+
+
 function hackpoint_sketch_save_cover(input,stream){
 	console.log('hey');
 	var li = input.closest('li');

+ 3 - 2
plugin/hackpoint/page.list.sketch.php

@@ -1,8 +1,9 @@
 <?php
-global $myUser;
+global $myUser,$conf;
 
 
 require_once(__DIR__.SLASH.'Sketch.class.php');
+
 ?>
 
 <div class="row">
@@ -55,7 +56,7 @@ require_once(__DIR__.SLASH.'Sketch.class.php');
 
         <div class="no-sketch hidden">
           <h2><i class="far fa-meh-blank"></i> Howww !</h2>
-          <p>Pas le moindre projet ici<br/> Il est temps de se mettre au boulot ....</p>
+          <p>Pas le moindre projet ici<br/> Il est temps de se mettre au boulot ...</p>
           <?php if($myUser->can('hackpoint', 'edit')) : ?>
             <a href="action.php?action=hackpoint_sketch_add" class="btn btn-success"><i class="fas fa-plus"></i> Ajouter un projet</a>
           <?php endif; ?>

+ 43 - 4
plugin/hackpoint/page.sheet.sketch.php

@@ -7,6 +7,10 @@ if(!$sketch) throw new Exception("Sketch supprimé ou inexistant");
 if(!$sketch->state &&  $sketch->creator != $myUser->login) throw new Exception("Sketch privé");
 
 $sketchClasses = $sketch->creator != $myUser->login ? "readonly":"editable";
+
+if(isset($_['embeded']) && $_['embeded'] == 1) $sketchClasses .= ' embeded';
+if(isset($_['sidebar']) && $_['sidebar'] == 0) $sketchClasses .= ' no-sidebar';
+
 ?>
 <div class="hackpoint <?php echo $sketchClasses; ?>">
 	
@@ -24,7 +28,7 @@ $sketchClasses = $sketch->creator != $myUser->login ? "readonly":"editable";
 					</li>
 				</ul>
 			</div>
-			<!--<a href="index.php?module=hackpoint&page=sheet.resource" class="btn btn-dark btn-add-resource"><i class="fas fa-plus"></i></a>-->
+			
 
 			<div class="btn-group dropright w-100 resource-dropdown">
 			  <button type="button" class="btn btn-dark btn-add-resource" title="Ajouter une ressource" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@@ -52,16 +56,29 @@ $sketchClasses = $sketch->creator != $myUser->login ? "readonly":"editable";
 
 							<div class="btn-group mr-2" role="group" aria-label="First group">
 								<div class="btn text-muted"><span class="sketch-preloader"><i class="far fast-spin fas fa-circle-notch"></i> Sauvegarde...</span></div>
-								<div class="btn text-muted btn-delete-sketch" title="Supprimer" onclick="hackpoint_sketch_delete(this);"><i class="far fa-trash-alt"></i></div>
+								
 							</div>
 							<div class="btn-group mr-2" role="group" aria-label="Properties">
 								<label for="state" class="input-group-text pointer m-0">
 									<input id="state" name="state" class="form-control editable-input" onclick="hackpoint_sketch_save();" <?php echo $sketch->state?'checked="checked"':''; ?> type="checkbox" data-type="checkbox"> Public
 								</label>
 							</div>
-							<div class="btn-group" role="group" aria-label="Save" onclick="$.message('info','En cours d\'implémentation...')">
-								<div onclick="" class="btn btn-success"><i class="fas fa-cogs"></i></div>
+							
+
+							<div class="btn-group" role="group" aria-label="Save" >
+
+								<div class="dropdown">
+									<div onclick="" class="btn btn-success" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fas fa-cogs"></i></div>
+									<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+									    <div class="dropdown-item pointer" onclick="hackpoint_sketch_share();"><i class="fas fa-share-alt"></i> Partager</div>
+									    <div class="dropdown-item pointer" onclick="hackpoint_sketch_download();"><i class="far fa-file-archive"></i> Télécharger</div>
+									    <div class="btn btn-delete-sketch dropdown-item" title="Supprimer" onclick="hackpoint_sketch_delete(this);"><i class="far fa-trash-alt"></i> Supprimer</div> 
+									</div>
+								</div>
+
 							</div>
+
+
 						</div>
 					</div>
 				</div>
@@ -76,3 +93,25 @@ $sketchClasses = $sketch->creator != $myUser->login ? "readonly":"editable";
 	</div>
 </div>
 
+<!-- MODALES -->
+
+<!-- Modale partage -->
+<div id="share-sketch-modal" class="hide" data-id="">
+  <div class="modalize-header">
+    <h4 class="text-uppercase font-weight-light"><i class="fas fa-share-alt"></i> Gestion des partages</h4>
+  </div>
+  <div class="modalize-content">
+  	<p>Vous pouvez intégrer ce sketch sur votre site web avec le code ci-dessous.<br/>
+  		<span class="font-weight-bold text-warning">nb :</span> Le sketch doit être en visibilité publique
+  	pour que les internautes puissent le consulter.</p>
+
+	<label><input type="checkbox" data-type="checkbox" class="share-menu-mode form-control"> n'afficher que la ressource courante  </label> 
+   	<textarea class="form-control share-input"></textarea>
+
+   	<div class="hidden shareCode"><a href="{{url}}?module=hackpoint&page=sheet.sketch&id={{sketch}}#resource={{resource}}"><small>Voir en taille réelle</small></a><br/><iframe frameborder="0" width="100%" align="center" height="400px" src="{{url}}?module=hackpoint&page=sheet.sketch&id={{sketch}}&embeded=1&sidebar={{menu}}#resource={{resource}}"></iframe></div>
+    
+    <div class="modalize-footer">
+      <div class="btn btn-dark">Fermer</div>
+    </div>
+  </div>
+</div>

+ 9 - 0
plugin/hackpoint/types/ArduinoType.class.php

@@ -48,6 +48,15 @@ void loop()
 	}
 
 
+	//Export vers un fichier brut
+	public static function toFile($resource){
+		$infos = self::manifest();
+		return array(
+			'name'=> slugify($resource->label).'.'.$infos['toExtension'],
+			'content' => html_entity_decode($resource->content)
+		);
+	}
+
 	
 }
 ?>

+ 21 - 6
plugin/hackpoint/types/FileType.class.php

@@ -7,6 +7,7 @@ class FileType {
 			'label' => 'Fichiers',
 			'description' => 'Fichiers attachés',
 			'fromExtension' => array('*'),
+			'toExtension' => 'zip',
 			'icon' => 'far fa-file-archive',
 			'color' => '#ffffff',
 			'background' => '#d7332d'
@@ -41,13 +42,27 @@ class FileType {
 	}
 
 	public static function toFile($resource){
+		global $myUser;
+		$infos = self::manifest();
+		$path = $resource->directory();
 
-		// $ext = getExt($resource->content);
-		// $infos = self::manifest();
-		// return array(
-		// 	'name'=> slugify($resource->label).'.'.$ext,
-		// 	'content' => file_exists(SKETCH_PATH.$resource->content) ? file_get_contents(SKETCH_PATH.$resource->content) : ''
-		// );
+		$filename = $resource->label.'-'.time().'.'.$infos['toExtension'];
+		$filepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.$filename;
+		$zip = new ZipArchive;
+		if(file_exists($filepath))unlink($filepath); 
+		$res = $zip->open($filepath, ZipArchive::CREATE);
+		if ($res === TRUE) {
+			foreach(glob($path.'/*') as $f)
+				$zip->addFile($f,basename($f));
+			
+			$zip->close();
+		}
+	
+		
+		return array(
+			'name'=> slugify($resource->label).'.'.$infos['toExtension'],
+			'content' => file_get_contents($filepath)
+		);
 	}
 
 	

+ 21 - 6
plugin/hackpoint/types/ImageType.class.php

@@ -7,6 +7,7 @@ class ImageType {
 			'label' => 'Schéma / Image',
 			'description' => 'Fichier image de type jpg/jpeg/png/bmp/gif/svg',
 			'fromExtension' => array('jpg','jpeg','png','bmp','gif','svg'),
+			'toExtension' => 'zip',
 			'icon' => 'fas fa-code-branch',
 			'color' => '#ffffff',
 			'background' => '#d7332d'
@@ -41,13 +42,27 @@ class ImageType {
 	}
 
 	public static function toFile($resource){
+		global $myUser;
+		$infos = self::manifest();
+		$path = $resource->directory();
 
-		// $ext = getExt($resource->content);
-		// $infos = self::manifest();
-		// return array(
-		// 	'name'=> slugify($resource->label).'.'.$ext,
-		// 	'content' => file_exists(SKETCH_PATH.$resource->content) ? file_get_contents(SKETCH_PATH.$resource->content) : ''
-		// );
+		$filename = slugify($resource->label).'-'.time().'.'.$infos['toExtension'];
+		$filepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.$filename;
+		$zip = new ZipArchive;
+		if(file_exists($filepath))unlink($filepath); 
+		$res = $zip->open($filepath, ZipArchive::CREATE);
+		if ($res === TRUE) {
+			foreach(glob($path.'/*') as $f)
+				$zip->addFile($f,basename($f));
+			
+			$zip->close();
+		}
+	
+		
+		return array(
+			'name'=> slugify($resource->label).'.'.$infos['toExtension'],
+			'content' => file_get_contents($filepath)
+		);
 	}
 
 	

+ 9 - 0
plugin/hackpoint/types/JsType.class.php

@@ -33,6 +33,15 @@ class JsType extends ReadmeType{
 		);
 	}
 
+	//Export vers un fichier brut
+	public static function toFile($resource){
+		$infos = self::manifest();
+		return array(
+			'name'=> slugify($resource->label).'.'.$infos['toExtension'],
+			'content' => html_entity_decode($resource->content)
+		);
+	}
+
 
 	
 }

+ 23 - 7
plugin/hackpoint/types/PartType.class.php

@@ -7,6 +7,7 @@ class PartType {
 			'label' => 'Composants',
 			'description' => 'Composants électroniques',
 			'fromExtension' => array('part'),
+			'toExtension' => 'md',
 			'icon' => 'fas fa-microchip',
 			'color' => '#ffffff',
 			'background' => '#2ecc71'
@@ -41,13 +42,28 @@ class PartType {
 	}
 
 	public static function toFile($resource){
-
-		// $ext = getExt($resource->content);
-		// $infos = self::manifest();
-		// return array(
-		// 	'name'=> slugify($resource->label).'.'.$ext,
-		// 	'content' => file_exists(SKETCH_PATH.$resource->content) ? file_get_contents(SKETCH_PATH.$resource->content) : ''
-		// );
+		require_once(__DIR__.SLASH.'..'.SLASH.'ResourcePart.class.php');
+		require_once(__DIR__.SLASH.'..'.SLASH.'Part.class.php');
+		global $myUser;
+		$infos = self::manifest();
+		
+		$content = '# '.strtoupper($resource->label).PHP_EOL.PHP_EOL;
+		
+		foreach(ResourcePart::loadAll(array('resource'=>$resource->id),  null,  null, array('*'), 1) as $resourcePart):
+			$part = $resourcePart->join('part');
+			$content .= '## '.$part->label.PHP_EOL;
+			if(isset($part->link) && !empty($part->link)) $content .= "\t".'* Url: ' .$part->link.PHP_EOL;
+			if(isset($part->brand) && !empty($part->brand)) $content .="\t".'* Marque: ' .$part->brand.PHP_EOL;
+			if(isset($part->price) && !empty($part->price)) $content .="\t".'* Prix moyen: '.$part->price.'€'.PHP_EOL;
+			$content .= '---';
+			$content .= PHP_EOL;
+		endforeach;
+	
+		
+		return array(
+			'name'=> slugify($resource->label).'.'.$infos['toExtension'],
+			'content' => $content
+		);
 	}
 
 	

Some files were not shown because too many files changed in this diff