Skip to content
Extraits de code Groupes Projets
Valider efe16101 rédigé par nicod's avatar nicod
Parcourir les fichiers

Gestion des rangs des blocs sur un objet

Code repris en grande partie du plugin medias (markup html, javascript et action)
TODO : mutualiser ce code relativement générique au niveau du core de SPIP ?
parent e72e7e7a
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
[x] Ajouter des blocs sous les objets liés [x] Ajouter des blocs sous les objets liés
[ ] Gérer les rangs des blocs sous les objets liés [x] Gérer les rangs des blocs sous les objets liés
[ ] Afficher les blocs sous les objets liés : largeur limitée, affichage simplifié + preview en popin ? [ ] Afficher les blocs sous les objets liés : largeur limitée, affichage simplifié + preview en popin ?
......
<?php
/**
* Action ordonnant un lien sur une table de liens
*
* @plugin Medias
* @copyright 2017
* @author Matthieu Marcillaud
* @licence GNU/GPL
* @package SPIP\Ordoc\Action
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
function action_ordonner_liens_blocs_dist() {
action_ordonner_liens_dist();
}
function action_ordonner_liens_dist() {
include_spip('inc/autoriser');
include_spip('base/objets');
include_spip('action/editer_liens');
// source (table spip_xx_liens)
$objet = objet_type(_request('objet_source'));
// objet lié
$objet_lie = objet_type(_request('objet_lie'));
$id_objet_lie = intval(_request('id_objet_lie'));
// ordre des éléments
$ordre = _request('ordre');
if (!$objet or !$objet_lie or !$id_objet_lie or !$ordre or !is_array($ordre) or !objet_associable($objet)) {
return envoyer_json_erreur(_T('medias:erreur_objet_absent') . ' ' . _T('medias:erreur_deplacement_impossible'));
}
if (!autoriser('modifier', $objet_lie, $id_objet_lie)) {
return envoyer_json_erreur(_T('medias:erreur_autorisation') . ' ' . _T('medias:erreur_deplacement_impossible'));
}
[$_id_objet, $table_liens] = objet_associable($objet);
$success = $errors = [];
$actuels = sql_allfetsel(
[$_id_objet . ' AS id', 'rang_lien'],
$table_liens,
[
sql_in($_id_objet, $ordre),
'objet = ' . sql_quote($objet_lie),
'id_objet = ' . sql_quote($id_objet_lie),
]
);
$futurs = array_flip($ordre);
// ordre de 1 à n (pas de 0 à n).
array_walk($futurs, function (&$v) {
$v++;
});
$updates = [];
foreach ($actuels as $l) {
if ($futurs[$l['id']] !== $l['rang_lien']) {
$updates[$l['id']] = $futurs[$l['id']];
}
}
if ($updates) {
foreach ($updates as $id => $ordre) {
sql_updateq(
$table_liens,
['rang_lien' => $ordre],
[
$_id_objet . ' = ' . $id,
'objet = ' . sql_quote($objet_lie),
'id_objet = ' . sql_quote($id_objet_lie),
]
);
}
}
return envoyer_json_envoi([
'done' => true,
'success' => $success,
'errors' => $errors,
]);
}
function envoyer_json_envoi($data) {
header('Content-Type: application/json; charset=' . $GLOBALS['meta']['charset']);
echo json_encode($data, JSON_THROW_ON_ERROR);
}
function envoyer_json_erreur($msg) {
return envoyer_json_envoi([
'done' => false,
'success' => [],
'errors' => [$msg],
]);
}
#HTTP_HEADER{Content-Type: text/javascript; charset=#CHARSET}
[(#REM)<script>/*
Gestion des listes de blocs :
- Gestion du tri par glisser-déposer
Markup :
- Listes : .liste_items.blocs
- Listes ordonnables : .liste_items.blocs.ordonner_rang_lien\[data-lien\]
*/]
/* Gestion du tri des listes de blocs et de leur enregistrement */
function ordonner_listes_blocs() {
if (typeof Sortable === 'function') {
$(".liste_items.blocs.ordonner_rang_lien[data-lien]").find('> .sortable').each(function () {
// détruire / recréer le sortable à chaque appel ajax
if (Sortable.get(this)) {
Sortable.get(this).destroy();
}
// pas de tri possible s'il n'y a qu'un seul élément.
if ($(this).find('> .item').length < 2) {
$(this).find('.deplacer-bloc').hide();
$(this).parent().find('.tout_desordonner').hide();
return true; // continue
} else {
$(this).find('.deplacer-bloc').show();
}
new Sortable(this, {
direction: 'vertical',
swapThreshold: .8,
ghostClass: "deplacer-bloc-placeholder",
onStart: function(event) {
$(event.item).addClass('bloc-en-mouvement');
},
onEnd: function(event) {
$(event.item).removeClass('bloc-en-mouvement');
},
onUpdate: function (event) {
const ordre = this.toArray();
const $items = $(event.from);
const $item = $(event.item);
// l'objet lié est indiqué dans l'attribut data-lien sur la liste
const [objet_lie, id_objet_lie] = $items.parents(".liste_items.blocs").data("lien").split("/");
const action = '[(#VAL{ordonner_liens_blocs}|generer_url_action{"", 1})]';
const params = {
objet_source: 'bloc',
objet_lie: objet_lie,
id_objet_lie: id_objet_lie,
ordre: ordre,
};
$item.animateLoading();
$.post({
url: action,
data: params,
dataType: 'json',
cache: false,
}).done(function(data) {
const couleur_origine = $item.css('background-color');
const couleur_erreur = $("<div class='remove'></div>").css('background-color');
const couleur_succes = $("<div class='append'></div>").css('background-color');
$item.endLoading(true);
if (data.errors.length) {
$item.css({backgroundColor: couleur_erreur}).animate({backgroundColor: couleur_origine}, 'normal', () => {
$item.css({backgroundColor: ''});
});
} else {
$item.css({backgroundColor: couleur_succes}).animate({backgroundColor: couleur_origine}, 'normal', () => {
$item.css({backgroundColor: ''});
});
$items.parent().find('.tout_desordonner').show();
}
});
}
});
// bouton "désordonner"
if ($(this).parent().find('.deplacer-bloc[data-rang!=0]').length) {
$(this).parent().find('.tout_desordonner').show();
} else {
$(this).parent().find('.tout_desordonner').hide();
}
});
}
}
/* Initialisation et relance en cas de chargement ajax */
if (window.jQuery) {
jQuery(function($){
if (!$.js_portfolio_blocs_charge) {
$.js_portfolio_blocs_charge = true;
if (typeof Sortable === "undefined") {
jQuery.getScript('[(#CHEMIN{prive/javascript/Sortable.js}|timestamp)]').done(ordonner_listes_blocs);
} else {
ordonner_listes_blocs();
}
onAjaxLoad(ordonner_listes_blocs);
}
});
}
<B> <B>
[<h2>(#GRAND_TOTAL|singulier_ou_pluriel{bloc:info_1_bloc,bloc:info_nb_blocs})</h2>] [<h2>(#GRAND_TOTAL|singulier_ou_pluriel{bloc:info_1_bloc,bloc:info_nb_blocs})</h2>]
<BOUCLE(BLOCS) {objet}{id_objet} {statut?} {par rang_lien}>
<div id="bloc#ID_BLOC">
#BOITE_OUVRIR{#INFO_TITRE{blocs_types,#ID_BLOCS_TYPE}}
#GENERER_BLOCK <div class="liste_items blocs ordonner_rang_lien" data-lien="#ENV{objet}/#ENV{id_objet}">
<div class="sortable">
<BOUCLE(BLOCS) {objet}{id_objet} {statut?} {par rang_lien}>
<div class="item bloc statut_#STATUT" id="bloc#ID_BLOC" data-id="#ID_BLOC">
<h3 class="titrem bloc__type">
[(#CHEMIN_IMAGE{bloc-16.png}|balise_img)]#INFO_TITRE{blocs_types,#ID_BLOCS_TYPE}
[(#AUTORISER{modifier,bloc,#ID_BLOC})
<span class="deplacer-bloc" data-rang="#RANG_LIEN">
<img src='#CHEMIN_IMAGE{deplacer-16.png}' width='16' height='16' alt='<:medias:ordonner_ce_document|attribut_html:>' title='<:medias:ordonner_ce_document|attribut_html:>' />
</span>
]
</h3>
[(#AUTORISER{modifier,bloc,#ID_BLOC}) #GENERER_BLOCK
[(#URL_ECRIRE{#VAL{bloc}|objet_info{url_edit},id_bloc=#ID_BLOC}|parametre_url{redirect,#SELF}|concat{'#bloc',#ID_BLOC}|icone_verticale{<:bloc:icone_modifier_bloc:/>,bloc,edit,right})]
]
#BOITE_FERMER [(#AUTORISER{modifier,bloc,#ID_BLOC})
<div class="deplacer-modifier">
[(#URL_ECRIRE{#VAL{bloc}|objet_info{url_edit},id_bloc=#ID_BLOC}|parametre_url{redirect,#SELF}|concat{'#bloc',#ID_BLOC}|icone_verticale{<:bloc:icone_modifier_bloc:/>,bloc,edit,right})]
</div>
]
</div>
</BOUCLE>
</div> </div>
</BOUCLE> </div>
</B> </B>
<div class="ajax"> <div class="ajax">
#FORMULAIRE_EDITER_BLOC{new,#OBJET,#ID_OBJET,#GET{redirect}} #FORMULAIRE_EDITER_BLOC{new,#OBJET,#ID_OBJET,#GET{redirect}}
</div> </div>
<script type="text/javascript">
/* Gestion du tri des blocs */
[(#INCLURE{fond=javascript/gestion_listes_blocs.js}|compacte{js})]
</script>
[(#REM)
Ce squelette definit les styles de l'espace prive
Note: l'entete "Vary:" sert a repousser l'entete par
defaut "Vary: Cookie,Accept-Encoding", qui est (un peu)
genant en cas de "rotation du cookie de session" apres
un changement d'IP (effet de clignotement).
<style>
]
#CACHE{3600*100,cache-client}
#HTTP_HEADER{Content-Type: text/css; charset=utf-8}
#HTTP_HEADER{Vary: Accept-Encoding}
#SET{claire,##ENV{couleur_claire,edf3fe}}
#SET{foncee,##ENV{couleur_foncee,3874b0}}
#SET{left,#ENV{ltr}|choixsiegal{left,left,right}}
#SET{right,#ENV{ltr}|choixsiegal{left,right,left}}
.liste_items.blocs {
}
.liste_items.blocs .item.bloc {
padding: calc(var(--spip-list-spacing-y) / 2) calc(var(--spip-list-spacing-x) / 2);
border:1px solid var(--spip-color-gray-light);
border-radius:5px;
margin-bottom: 1rem;
}
.liste_items.blocs .item.bloc .bloc__type {
margin-bottom: 1rem;
}
.deplacer-bloc {
display: inline-flex;
float: var(--spip-right);
margin-top: 1px;
cursor: move;
}
.item.deplacer-bloc-placeholder { background-color: var(--spip-color-theme-lighter); }
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter