Recherche avancée

Médias (91)

Autres articles (101)

  • Use, discuss, criticize

    13 avril 2011, par

    Talk to people directly involved in MediaSPIP’s development, or to people around you who could use MediaSPIP to share, enhance or develop their creative projects.
    The bigger the community, the more MediaSPIP’s potential will be explored and the faster the software will evolve.
    A discussion list is available for all exchanges between users.

  • Le plugin : Podcasts.

    14 juillet 2010, par

    Le problème du podcasting est à nouveau un problème révélateur de la normalisation des transports de données sur Internet.
    Deux formats intéressants existent : Celui développé par Apple, très axé sur l’utilisation d’iTunes dont la SPEC est ici ; Le format "Media RSS Module" qui est plus "libre" notamment soutenu par Yahoo et le logiciel Miro ;
    Types de fichiers supportés dans les flux
    Le format d’Apple n’autorise que les formats suivants dans ses flux : .mp3 audio/mpeg .m4a audio/x-m4a .mp4 (...)

  • Des sites réalisés avec MediaSPIP

    2 mai 2011, par

    Cette page présente quelques-uns des sites fonctionnant sous MediaSPIP.
    Vous pouvez bien entendu ajouter le votre grâce au formulaire en bas de page.

Sur d’autres sites (5337)

  • Matomo analytics for wordpress

    15 octobre 2019, par Matomo Core Team — Community

    Self-hosting web analytics got a whole lot easier ! Introducing Matomo for WordPress

    Be the first to try it out ! Your feedback is much needed and appreciated

    Get a fully functioning Matomo (which is comparable to Google Analytics) in seconds ! How ? With the new Matomo Analytics for WordPress plugin. 

    Web analytics in WordPress has never been easier to get, or more powerful. Matomo Analytics for WordPress is the one-stop problem solver. It’ll save you time, money and give you the insights to help your website or business succeed. 

    Best of all, we get to further the goal of decentralising the internet. Our hope is for Matomo Analytics for WordPress to spread far and wide. We’re so excited that more and more people can now get their hands on this powerful, free, open-source analytics platform, in a few clicks !

    Download now and check it out !

    What do you get ?

    • No more signing up to third party analytics service (like Google)
    • No more sending away your valuable data to a third party service (like Google)
    • Easy setup – install with a few clicks, no tracking code installation or developer knowledge needed
    • 100% accurate data – no data sampling and no data limits 
    • Full data ownership – all data is stored on your servers and no one else can see your data
    • Privacy protection / GDPR compliance
    • Ecommerce tracking out-of-the-box (Woocommerce, Easy Digital Downloads, and MemberPress) and we’re keen to add many more over time
    • Powerful features – segmenting, comparing reports, different visualisations, real-time reports, visit logs and visitor profiles, Matomo Tag Manager, dashboards, data export, APIs, and many more
    • Compared to other WordPress solutions we don’t charge you extra for basic features that should work out-of-the-box
    • Just like Matomo On-Premise, Matomo Analytics for WordPress is free

    We need your feedback !

    We all know and love the versatility of WordPress – with over 55,000 plugins and all the different ways of hosting it. However, with this great versatility comes the potential for things to be missed, so we’re keen to hear your feedback.

    Thank you ! We really appreciate your help on this ❤️

    How do you get Matomo Analytics for WordPress ?

    You can then upload it in your WordPress by going to “Plugins => Add New”. During the upload, if you get an error like “Are you sure you want to do this ?”, we recommend you upload the extracted zip file on to your server and into your ‘wp-content/plugins’ folder manually using ftp or ssh. Make sure the plugin name is ‘matomo’.

    All you need is at least WordPress 4.8 and PHP 7.0 or later. MySQL 5.1+ is recommended. 

    The source code is available at : https://github.com/matomo-org/wp-matomo/

    In perfect harmony : Matomo and WordPress

    Matomo Analytics for WordPress

    The idea for this started two years ago when we realised the similarities between the Matomo and WordPress project. 

    Not only from a technological point of view – where both are based on PHP and MySQL and can be extended using plugins – but also from a philosophical, license and values point of view. We both believe in privacy, security, data ownership, openness, transparency, having things working out-of-the-box, simplicity etc. 

    WordPress is currently used on approximately 30% of all websites. Many of them use the self-hosted open-source WordPress version. Giving everyone in this market the opportunity to easily get a powerful web analytics platform for free, means a lot to us. We believe WordPress users get a real choice besides the standard solution of Google Analytics, and it furthers our effort and goal of decentralising the internet. 

    We’re hoping more people will be empowered to protect user privacy, have access to a great free and open-source tool, and keep control of data in their own hands.

    We hope you feel the same. Help us spread the word to your friends and get them in on this awesome new project !

    Share on facebook
    Share on twitter
    Share on linkedin

    FAQs

    Isn’t there already a WP-Matomo plugin for WordPress available ?

    Yes, the existing WP-Matomo (WP-Piwik) plugin is an awesome plugin to connect your existing Matomo On-Premise or Matomo Cloud account with WordPress. The difference is that this new plugin installs Matomo Analytics fully in your WordPress. So you get the convenience of having a powerful analytics platform within your WordPress.

    We highly recommend you install this new plugin if you use WordPress and are not running Matomo yet. 

    If you are already using Matomo on our Cloud or On-Premise, we’d still highly recommend you use WP-Matomo (WP-Piwik). So that you get an easier way of inserting the tracking code into your WordPress site and get insights faster.

    I have a high traffic website, will it be an issue ?

    If you have a lot of traffic, we’d advise you to install Matomo On-Premise separately. There’s no specific traffic threshold we can give you on when it’s better to use Matomo On-Premise. It really depends on your server. 

    We reckon if you have more than 500,000 page views a month, you may want to think about using Matomo On-Premise with WP-Matomo instead, but this is just an estimate. In general, if the load on your server is already quite high, then it might be better to install Matomo on a separate server. See also recommended server sizing for running Matomo.

    How do I report a bug or request a new feature in Matomo for WordPress ?

    Please create an issue, on our repository whenever you find a bug or if you have any suggestion or ideas of improvement. We want to build an outstanding analytics experience for WordPress !

    Have another question you’re dying to ask ? The Matomo for WordPress FAQ page might have the answer you need. 

    Matomo Analytics for WordPress newsletter

    Get ahead of the crowd – signup to our exclusive Matomo for WordPress newsletter to get the latest updates on this exciting new project.

    &lt;script type=&quot;text/javascript&quot;&gt;<br />
    (function(global) {<br />
     function serialize(form){if(!form||form.nodeName!==&quot;FORM&quot;){return }var i,j,q=[];for(i=form.elements.length-1;i&gt;=0;i=i-1){if(form.elements[i].name===&quot;&quot;){continue}switch(form.elements[i].nodeName){case&quot;INPUT&quot;:switch(form.elements[i].type){case&quot;text&quot;:case&quot;hidden&quot;:case&quot;password&quot;:case&quot;button&quot;:case&quot;reset&quot;:case&quot;submit&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break;case&quot;checkbox&quot;:case&quot;radio&quot;:if(form.elements[i].checked){q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value))}break;case&quot;file&quot;:break}break;case&quot;TEXTAREA&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break;case&quot;SELECT&quot;:switch(form.elements[i].type){case&quot;select-one&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break;case&quot;select-multiple&quot;:for(j=form.elements[i].options.length-1;j&gt;=0;j=j-1){if(form.elements[i].options[j].selected){q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].options[j].value))}}break}break;case&quot;BUTTON&quot;:switch(form.elements[i].type){case&quot;reset&quot;:case&quot;submit&quot;:case&quot;button&quot;:q.push(form.elements[i].name+&quot;=&quot;+encodeURIComponent(form.elements[i].value));break}break}}return q.join(&quot;&amp;&quot;)};<br />
    <br />
    <br />
     function extend(destination, source) {<br />
       for (var prop in source) {<br />
         destination[prop] = source[prop];<br />
       }<br />
     }<br />
    <br />
     if (!Mimi) var Mimi = {};<br />
     if (!Mimi.Signups) Mimi.Signups = {};<br />
    <br />
     Mimi.Signups.EmbedValidation = function() {<br />
       this.initialize();<br />
    <br />
       var _this = this;<br />
       if (document.addEventListener) {<br />
         this.form.addEventListener('submit', function(e){<br />
           _this.onFormSubmit(e);<br />
         });<br />
       } else {<br />
         this.form.attachEvent('onsubmit', function(e){<br />
           _this.onFormSubmit(e);<br />
         });<br />
       }<br />
     };<br />
    <br />
     extend(Mimi.Signups.EmbedValidation.prototype, {<br />
       initialize: function() {<br />
         this.form         = document.getElementById('ema_signup_form');<br />
         this.submit       = document.getElementById('webform_submit_button');<br />
         this.callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());<br />
         this.validEmail   = /.+@.+\..+/<br />
       },<br />
    <br />
       onFormSubmit: function(e) {<br />
         e.preventDefault();<br />
    <br />
         this.validate();<br />
         if (this.isValid) {<br />
           this.submitForm();<br />
         } else {<br />
           this.revalidateOnChange();<br />
         }<br />
       },<br />
    <br />
       validate: function() {<br />
         this.isValid = true;<br />
         this.emailValidation();<br />
         this.fieldAndListValidation();<br />
         this.updateFormAfterValidation();<br />
       },<br />
    <br />
       emailValidation: function() {<br />
         var email = document.getElementById('signup_email');<br />
    <br />
         if (this.validEmail.test(email.value)) {<br />
           this.removeTextFieldError(email);<br />
         } else {<br />
           this.textFieldError(email);<br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       fieldAndListValidation: function() {<br />
         var fields = this.form.querySelectorAll('.mimi_field.required');<br />
    <br />
         for (var i = 0; i &lt; fields.length; ++i) {<br />
           var field = fields[i],<br />
               type  = this.fieldType(field);<br />
           if (type === 'checkboxes' || type === 'radio_buttons' || type === 'age_check') {<br />
             this.checkboxAndRadioValidation(field);<br />
           } else {<br />
             this.textAndDropdownValidation(field, type);<br />
           }<br />
         }<br />
       },<br />
    <br />
       fieldType: function(field) {<br />
         var type = field.querySelectorAll('.field_type');<br />
    <br />
         if (type.length) {<br />
           return type[0].getAttribute('data-field-type');<br />
         } else if (field.className.indexOf('checkgroup') &gt;= 0) {<br />
           return 'checkboxes';<br />
         } else {<br />
           return 'text_field';<br />
         }<br />
       },<br />
    <br />
       checkboxAndRadioValidation: function(field) {<br />
         var inputs   = field.getElementsByTagName('input'),<br />
             selected = false;<br />
    <br />
         for (var i = 0; i &lt; inputs.length; ++i) {<br />
           var input = inputs[i];<br />
           if((input.type === 'checkbox' || input.type === 'radio') &amp;&amp; input.checked) {<br />
             selected = true;<br />
           }<br />
         }<br />
    <br />
         if (selected) {<br />
           field.className = field.className.replace(/ invalid/g, '');<br />
         } else {<br />
           if (field.className.indexOf('invalid') === -1) {<br />
             field.className += ' invalid';<br />
           }<br />
    <br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       textAndDropdownValidation: function(field, type) {<br />
         var inputs = field.getElementsByTagName('input');<br />
    <br />
         for (var i = 0; i &lt; inputs.length; ++i) {<br />
           var input = inputs[i];<br />
           if (input.name.indexOf('signup') &gt;= 0) {<br />
             if (type === 'text_field') {<br />
               this.textValidation(input);<br />
             } else {<br />
               this.dropdownValidation(field, input);<br />
             }<br />
           }<br />
         }<br />
         this.htmlEmbedDropdownValidation(field);<br />
       },<br />
    <br />
       textValidation: function(input) {<br />
         if (input.id === 'signup_email') return;<br />
    <br />
         if (input.value) {<br />
           this.removeTextFieldError(input);<br />
         } else {<br />
           this.textFieldError(input);<br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       dropdownValidation: function(field, input) {<br />
         if (input.value) {<br />
           field.className = field.className.replace(/ invalid/g, '');<br />
         } else {<br />
           if (field.className.indexOf('invalid') === -1) field.className += ' invalid';<br />
           this.onSelectCallback(input);<br />
           this.isValid = false;<br />
         }<br />
       },<br />
    <br />
       htmlEmbedDropdownValidation: function(field) {<br />
         var dropdowns = field.querySelectorAll('.mimi_html_dropdown');<br />
         var _this = this;<br />
    <br />
         for (var i = 0; i &lt; dropdowns.length; ++i) {<br />
           var dropdown = dropdowns[i];<br />
    <br />
           if (dropdown.value) {<br />
             field.className = field.className.replace(/ invalid/g, '');<br />
           } else {<br />
             if (field.className.indexOf('invalid') === -1) field.className += ' invalid';<br />
             this.isValid = false;<br />
             dropdown.onchange = (function(){ _this.validate(); });<br />
           }<br />
         }<br />
       },<br />
    <br />
       textFieldError: function(input) {<br />
         input.className   = 'required invalid';<br />
         input.placeholder = input.getAttribute('data-required-field');<br />
       },<br />
    <br />
       removeTextFieldError: function(input) {<br />
         input.className   = 'required';<br />
         input.placeholder = '';<br />
       },<br />
    <br />
       onSelectCallback: function(input) {<br />
         if (typeof Widget === 'undefined' || !Widget.BasicDropdown) return;<br />
    <br />
         var dropdownEl = input.parentNode,<br />
             instances  = Widget.BasicDropdown.instances,<br />
             _this = this;<br />
    <br />
         for (var i = 0; i &lt; instances.length; ++i) {<br />
           var instance = instances[i];<br />
           if (instance.wrapperEl === dropdownEl) {<br />
             instance.onSelect = function(){ _this.validate() };<br />
           }<br />
         }<br />
       },<br />
    <br />
       updateFormAfterValidation: function() {<br />
         this.form.className   = this.setFormClassName();<br />
         this.submit.value     = this.submitButtonText();<br />
         this.submit.disabled  = !this.isValid;<br />
         this.submit.className = this.isValid ? 'submit' : 'disabled';<br />
       },<br />
    <br />
       setFormClassName: function() {<br />
         var name = this.form.className;<br />
    <br />
         if (this.isValid) {<br />
           return name.replace(/\s?mimi_invalid/, '');<br />
         } else {<br />
           if (name.indexOf('mimi_invalid') === -1) {<br />
             return name += ' mimi_invalid';<br />
           } else {<br />
             return name;<br />
           }<br />
         }<br />
       },<br />
    <br />
       submitButtonText: function() {<br />
         var invalidFields = document.querySelectorAll('.invalid'),<br />
             text;<br />
    <br />
         if (this.isValid || !invalidFields) {<br />
           text = this.submit.getAttribute('data-default-text');<br />
         } else {<br />
           if (invalidFields.length || invalidFields[0].className.indexOf('checkgroup') === -1) {<br />
             text = this.submit.getAttribute('data-invalid-text');<br />
           } else {<br />
             text = this.submit.getAttribute('data-choose-list');<br />
           }<br />
         }<br />
         return text;<br />
       },<br />
    <br />
       submitForm: function() {<br />
         this.formSubmitting();<br />
    <br />
         var _this = this;<br />
         window[this.callbackName] = function(response) {<br />
           delete window[this.callbackName];<br />
           document.body.removeChild(script);<br />
           _this.onSubmitCallback(response);<br />
         };<br />
    <br />
         var script = document.createElement('script');<br />
         script.src = this.formUrl('json');<br />
         document.body.appendChild(script);<br />
       },<br />
    <br />
       formUrl: function(format) {<br />
         var action  = this.form.action;<br />
         if (format === 'json') action += '.json';<br />
         return action + '?callback=' + this.callbackName + '&amp;' + serialize(this.form);<br />
       },<br />
    <br />
       formSubmitting: function() {<br />
         this.form.className  += ' mimi_submitting';<br />
         this.submit.value     = this.submit.getAttribute('data-submitting-text');<br />
         this.submit.disabled  = true;<br />
         this.submit.className = 'disabled';<br />
       },<br />
    <br />
       onSubmitCallback: function(response) {<br />
         if (response.success) {<br />
           this.onSubmitSuccess(response.result);<br />
         } else {<br />
           top.location.href = this.formUrl('html');<br />
         }<br />
       },<br />
    <br />
       onSubmitSuccess: function(result) {<br />
         if (result.has_redirect) {<br />
           top.location.href = result.redirect;<br />
         } else if(result.single_opt_in || !result.confirmation_html) {<br />
           this.disableForm();<br />
           this.updateSubmitButtonText(this.submit.getAttribute('data-thanks'));<br />
         } else {<br />
           this.showConfirmationText(result.confirmation_html);<br />
         }<br />
       },<br />
    <br />
       showConfirmationText: function(html) {<br />
         var fields = this.form.querySelectorAll('.mimi_field');<br />
    <br />
         for (var i = 0; i &lt; fields.length; ++i) {<br />
           fields[i].style['display'] = 'none';<br />
         }<br />
    <br />
         (this.form.querySelectorAll('fieldset')[0] || this.form).innerHTML = html;<br />
       },<br />
    <br />
       disableForm: function() {<br />
         var elements = this.form.elements;<br />
         for (var i = 0; i &lt; elements.length; ++i) {<br />
           elements[i].disabled = true;<br />
         }<br />
       },<br />
    <br />
       updateSubmitButtonText: function(text) {<br />
         this.submit.value = text;<br />
       },<br />
    <br />
       revalidateOnChange: function() {<br />
         var fields = this.form.querySelectorAll(&quot;.mimi_field.required&quot;),<br />
             _this = this;<br />
    <br />
         var onTextFieldChange = function() {<br />
           if (this.getAttribute('name') === 'signup[email]') {<br />
             if (_this.validEmail.test(this.value)) _this.validate();<br />
           } else {<br />
             if (this.value.length === 1) _this.validate();<br />
           }<br />
         }<br />
    <br />
         for (var i = 0; i &lt; fields.length; ++i) {<br />
           var inputs = fields[i].getElementsByTagName('input');<br />
           for (var j = 0; j &lt; inputs.length; ++j) {<br />
             if (this.fieldType(fields[i]) === 'text_field') {<br />
               inputs[j].onkeyup = onTextFieldChange;<br />
               inputs[j].onchange = onTextFieldChange; <br />
             } else {<br />
               inputs[j].onchange = function(){ _this.validate() };<br />
             }<br />
           }<br />
         }<br />
       }<br />
     });<br />
    <br />
     if (document.addEventListener) {<br />
       document.addEventListener(&quot;DOMContentLoaded&quot;, function() {<br />
         new Mimi.Signups.EmbedValidation();<br />
       });<br />
     }<br />
     else {<br />
       window.attachEvent('onload', function() {<br />
         new Mimi.Signups.EmbedValidation();<br />
       });<br />
     }<br />
    })(this);<br />
    &lt;/script&gt;
  • Evolution #4391 (Nouveau) : Squelettes de la dist : améliorer le markup et passer à BEM

    13 octobre 2019, par tcharlss (*´_ゝ`)

    Hello,

    En voulant créer des nouveaux thèmes pour les squelettes de la dist, j’ai rencontré des limitations dûes au markup actuel.

    Par exemple, certains éléments sans classe sont impossibles à cibler, il y a des retours lignes en dur, etc.
    En certains endroits, cela limite pas mal les possibilités.
    J’aimerais lancer un petit refactoring du markup afin qu’il soit plus facile de thémer les squelettes et de maintenir les styles.

    Il s’agirait principalement d’améliorer la nomenclature des classes, en changeant le moins possible le markup afin que les thèmes actuels restent compatibles (ou au prix d’adaptations minimes).
    On ajouterait donc des nouvelles classes, sans supprimer les classes actuelles (dans un 1er temps tout du moins ?).
    Cela pourrait être l’occasion de passer à la méthodologie BEM pour la nomenclature des classes.

    Exemple n°1

    Exemple avec le copyright et les liens dans le footer.
    Actuellement, il n’y a pas de classe autour du copyright, les liens ne sont pas encapsulés dans un conteneur, et les séparateurs « | » n’ont pas de classe n’ont plus.
    Il est donc quasiment impossible de changer l’agencement général, de changer l’apparence des séparateurs, etc.

    <span class="CodeRay"><span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">colophon</span><span class="delimiter">"</span></span><span class="tag">></span>
       2009 - 2019 Thèmes SPIP
       <span class="tag"><br /></span>
       <span class="tag">span> <span class="attribute-name">rel</span>=<span class="string"><span class="delimiter">"</span><span class="content">contents</span><span class="delimiter">"</span></span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">first</span><span class="delimiter">"</span></span><span class="tag">></span>Plan du site<span class="tag"></span>    | <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">ecrire/</span><span class="delimiter">"</span></span><span class="tag">></span>Espace privé<span class="tag"></span> | <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span> <span class="attribute-name">rel</span>=<span class="string"><span class="delimiter">"</span><span class="content">nofollow</span><span class="delimiter">"</span></span><span class="tag">></span>Se déconnecter<span class="tag"></span> |
    <span class="tag">span> <span class="attribute-name">rel</span>=<span class="string"><span class="delimiter">"</span><span class="content">nofollow</span><span class="delimiter">"</span></span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span><span class="tag">></span>Contact<span class="tag"></span> | <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span> <span class="attribute-name">rel</span>=<span class="string"><span class="delimiter">"</span><span class="content">alternate</span><span class="delimiter">"</span></span> <span class="attribute-name">title</span>=<span class="string"><span class="delimiter">"</span><span class="content">Syndiquer tout le site</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">last</span><span class="delimiter">"</span></span><span class="tag">></span>RSS<span class="entity">&amp;nbsp;</span>2.0<span class="tag"></span>
    <span class="tag"></span>
    </span></span></span></span></span></span></span>

    Voici ce que ça pourrait donner en refactorisant :

    • Le copyright est encapsulé dans un span
    • Les liens sont considérés comme faisant partie d’un menu, et sont donc encapsulés dans un composant « menu »
    • Les séparateurs sont fait en CSS, pas en dur dans le HTML
    <span class="CodeRay"><span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">colophon</span><span class="delimiter">"</span></span><span class="tag">></span>
       <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">colophon__coyright</span><span class="delimiter">"</span></span><span class="tag">></span>2009 - 2019 Thèmes SPIP<span class="tag"></span></span>
       <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">colophon__menu</span><span class="delimiter">"</span></span><span class="tag">></span>
           <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu menu_footer</span><span class="delimiter">"</span></span><span class="tag">></span>
               <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu__item menu__item_plan</span><span class="delimiter">"</span></span><span class="tag">></span>
                   <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu__link first</span><span class="delimiter">"</span></span> <span class="attribute-name">rel</span>=<span class="string"><span class="delimiter">"</span><span class="content">contents</span><span class="delimiter">"</span></span><span class="tag">></span>Plan du site<span class="tag"></span>
               <span class="tag"></span>
               <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu__item menu__item_backoffice</span><span class="delimiter">"</span></span><span class="tag">></span>
                   <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span><span class="tag">></span>Espace privé<span class="tag"></span>
               <span class="tag"></span>
               <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu__item menu__item_logout</span><span class="delimiter">"</span></span><span class="tag">></span>
                   <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu__link</span><span class="delimiter">"</span></span> <span class="attribute-name">rel</span>=<span class="string"><span class="delimiter">"</span><span class="content">nofollow</span><span class="delimiter">"</span></span><span class="tag">></span>Se déconnecter<span class="tag"></span>
               <span class="tag"></span>
               <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu__item menu__item_contact</span><span class="delimiter">"</span></span><span class="tag">></span>
                   <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu__link</span><span class="delimiter">"</span></span> <span class="attribute-name">rel</span>=<span class="string"><span class="delimiter">"</span><span class="content">nofollow</span><span class="delimiter">"</span></span><span class="tag">></span>Contact<span class="tag"></span>
               <span class="tag"></span>
               <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu__item menu__item_rss</span><span class="delimiter">"</span></span><span class="tag">></span>
                   <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">menu__link last</span><span class="delimiter">"</span></span> <span class="attribute-name">rel</span>=<span class="string"><span class="delimiter">"</span><span class="content">alternate</span><span class="delimiter">"</span></span> <span class="attribute-name">title</span>=<span class="string"><span class="delimiter">"</span><span class="content">Syndiquer tout le site</span><span class="delimiter">"</span></span><span class="tag">></span>RSS<span class="entity">&amp;nbsp;</span>2.0<span class="tag"></span>
               <span class="tag"></span>
           <span class="tag"></span>
       <span class="tag"></span>
    <span class="tag"></span>
    </span></span></span></span></span></span></span></span></span></span></span></span></span></span>

    Avec ça, on peut faire beaucoup plus de choses : afficher le copyright et le menu côte-à-côte ou l’un sous l’autre, afficher le menu à l’horizontale ou à la verticale, choisir l’apparence des séparateurs, etc.

    Exemple n°2

    Autre exemple avec les résumés d’articles.

    <span class="CodeRay"><span class="tag">span> <span class="attribute-name">dir</span>=<span class="string"><span class="delimiter">"</span><span class="content">ltr</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">hentry clearfix text-left</span><span class="delimiter">"</span></span><span class="tag">></span>  
       <span class="tag"><strong></strong></span>
           <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span><span class="tag">></span>
               <span class="tag">span> <span class="attribute-name">src</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">spip_logo</span><span class="delimiter">"</span></span> <span class="attribute-name">alt</span>=<span class="string"><span class="delimiter">"</span><span class="delimiter">"</span></span> <span class="attribute-name">width</span>=<span class="string"><span class="delimiter">"</span><span class="content">150</span><span class="delimiter">"</span></span> <span class="attribute-name">height</span>=<span class="string"><span class="delimiter">"</span><span class="content">185</span><span class="delimiter">"</span></span><span class="tag">></span>
               Joie entourée d’angoisses (1)
           <span class="tag"></span>
       <span class="tag"></span>
       <span class="tag"><br /></span><span class="tag"><small></small></span>6 mai 2009, par  Victor Hugo<span class="tag"></span>
       <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">introduction entry-content</span><span class="delimiter">"</span></span><span class="tag">></span>
           <span class="tag"><p></p></span>
               Lorem ipsum<span class="entity">&amp;nbsp;</span>(...)
           <span class="tag"></span>
       <span class="tag"></span>
    <span class="tag"></span>
    </span></span></span></span></span>

    En refactorisant :

    • Le composant de base est nommé « resume », et on voit qu’il s’agit d’une variante « article ».
    • Tous les éléments ont une classe.
    • Le titre est encapsulé dans un <h3></h3> plutôt qu’un <strong></strong>.
    • L’image est sortie du titre, et sa largeur n’est pas limitée à 150px (ça se ferait en CSS).
    <span class="CodeRay"><span class="tag">span> <span class="attribute-name">dir</span>=<span class="string"><span class="delimiter">"</span><span class="content">ltr</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">resume resume_article hentry clearfix text-left</span><span class="delimiter">"</span></span><span class="tag">></span>  
       <span class="tag">span> <span class="attribute-name">src</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">resume__logo spip_logo</span><span class="delimiter">"</span></span> <span class="attribute-name">alt</span>=<span class="string"><span class="delimiter">"</span><span class="delimiter">"</span></span> <span class="attribute-name">width</span>=<span class="string"><span class="delimiter">"</span><span class="content">960</span><span class="delimiter">"</span></span> <span class="attribute-name">height</span>=<span class="string"><span class="delimiter">"</span><span class="content">480</span><span class="delimiter">"</span></span><span class="tag">></span>
       <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">resume__title</span><span class="delimiter">"</span></span><span class="tag">></span>
           <span class="tag">span> <span class="attribute-name">href</span>=<span class="string"><span class="delimiter">"</span><span class="content">...</span><span class="delimiter">"</span></span><span class="tag">></span>
               Joie entourée d’angoisses (1)
           <span class="tag"></span>
       <span class="tag"></span>
       <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">resume__publication</span><span class="delimiter">"</span></span><span class="tag">></span>
           <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">resume__date</span><span class="delimiter">"</span></span><span class="tag">></span>6 mai 2009<span class="tag"></span></span><span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">sep</span><span class="delimiter">"</span></span><span class="tag">></span>,<span class="tag"></span></span> <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">resume__author</span><span class="delimiter">"</span></span><span class="tag">></span>par Victor Hugo<span class="tag"></span></span>
       <span class="tag"></span>
       <span class="tag">span> <span class="attribute-name">class</span>=<span class="string"><span class="delimiter">"</span><span class="content">resume__content introduction entry-content</span><span class="delimiter">"</span></span><span class="tag">></span>
           <span class="tag"><p></p></span>
               Lorem ipsum<span class="entity">&amp;nbsp;</span>(...)
           <span class="tag"></span>
       <span class="tag"></span>
    <span class="tag"></span>
    </span></span></span></span></span></span></span>

    Voilà, ce ne sont que des exemples et non pas des propositions définitives.
    C’est juste pour montrer la direction dans laquelle aller.

    HTML5

    Il est tentant de vouloir en profiter pour passer en HTML5, mais je préfère laisser cet aspect à part (il y a déjà des tickets dessus je pense).

    Français/anglais ?

    Actuellement pour la nomenclature des classes, il y a un mélange de français et d’anglais. Personnellement, ça ne me dérange pas :)
    J’ai arrêté d’essayer de tout franciser à tout prix, je préfère partir sur une base en anglais, avec quelques éléments en français quand il n’y a a pas le choix (par exemple quand on fait référence aux objets spip : breve, rubrique, etc.).

    Cahier des charges

    • Faire en sorte que les thèmes existants restent globalement compatibles (moyennant peu d’adaptations).
    • Passer la nomenclature des classes à BEM.
    • Ajouter des classes sur tous les éléments n’en ayant pas.
    • Retirer les retours ligne en dur : <br />.
    • Travailler dans une branche nommée « bem » du dépôt git : https://git.spip.net/SPIP/dist/
    • Pas de HTML5 pour l’instant.
    • Classes en english avec des exceptions en français
  • ffmpeg MKV to MP4 format conversion issues

    28 septembre 2019, par Lucas Lecce

    I converted a 3Gb MKV video file to MP4 format using the following ffmpeg command :

    ffmpeg -i input.mkv -c: v libx264 -crf 23 -c: a aac -movflags faststart output.mp4
    ffmpeg -i input.mkv -acodec copy -vcodec copy output.mp4
    ffmpeg version N-95111-g87ddf9f1ef Copyright (c) 2000-2019 the FFmpeg developers
     built with gcc 9.2.1 (GCC) 20190918
     configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt --enable-amf
     libavutil      56. 35.100 / 56. 35.100
     libavcodec     58. 59.100 / 58. 59.100
     libavformat    58. 33.100 / 58. 33.100
     libavdevice    58.  9.100 / 58.  9.100
     libavfilter     7. 59.100 /  7. 59.100
     libswscale      5.  6.100 /  5.  6.100
     libswresample   3.  6.100 /  3.  6.100
     libpostproc    55.  6.100 / 55.  6.100
    Input #0, matroska,webm, from 'input.mkv':
     Metadata:
       title           : claucha75
       encoder         : libebml v1.3.5 + libmatroska v1.4.8
       creation_time   : 2018-01-23T22:07:33.000000Z
     Duration: 01:37:13.89, start: 0.000000, bitrate: 5044 kb/s
       Stream #0:0: Video: h264 (High), yuv420p(tv, bt709, progressive), 1920x1080, SAR 1:1 DAR 16:9, 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc (default)
       Metadata:
         title           : claucha75
         BPS             : 4146894
         BPS-eng         : 4146894
         DURATION        : 01:37:12.952000000
         DURATION-eng    : 01:37:12.952000000
         NUMBER_OF_FRAMES: 139851
         NUMBER_OF_FRAMES-eng: 139851
         NUMBER_OF_BYTES : 3023579528
         NUMBER_OF_BYTES-eng: 3023579528
         _STATISTICS_WRITING_APP: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_APP-eng: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_DATE_UTC: 2018-01-23 22:07:33
         _STATISTICS_WRITING_DATE_UTC-eng: 2018-01-23 22:07:33
         _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
         _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
       Stream #0:1(spa): Audio: ac3, 48000 Hz, 5.1(side), fltp, 448 kb/s (default)
       Metadata:
         title           : Latino
         BPS             : 448000
         BPS-eng         : 448000
         DURATION        : 01:37:13.888000000
         DURATION-eng    : 01:37:13.888000000
         NUMBER_OF_FRAMES: 182309
         NUMBER_OF_FRAMES-eng: 182309
         NUMBER_OF_BYTES : 326697728
         NUMBER_OF_BYTES-eng: 326697728
         _STATISTICS_WRITING_APP: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_APP-eng: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_DATE_UTC: 2018-01-23 22:07:33
         _STATISTICS_WRITING_DATE_UTC-eng: 2018-01-23 22:07:33
         _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
         _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
       Stream #0:2(eng): Audio: ac3, 48000 Hz, 5.1(side), fltp, 448 kb/s
       Metadata:
         title           : Ingles
         BPS             : 448000
         BPS-eng         : 448000
         DURATION        : 01:37:13.856000000
         DURATION-eng    : 01:37:13.856000000
         NUMBER_OF_FRAMES: 182308
         NUMBER_OF_FRAMES-eng: 182308
         NUMBER_OF_BYTES : 326695936
         NUMBER_OF_BYTES-eng: 326695936
         _STATISTICS_WRITING_APP: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_APP-eng: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_DATE_UTC: 2018-01-23 22:07:33
         _STATISTICS_WRITING_DATE_UTC-eng: 2018-01-23 22:07:33
         _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
         _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
       Stream #0:3(spa): Subtitle: subrip
       Metadata:
         title           : Sub. Latino
         BPS             : 58
         BPS-eng         : 58
         DURATION        : 01:27:56.723000000
         DURATION-eng    : 01:27:56.723000000
         NUMBER_OF_FRAMES: 1048
         NUMBER_OF_FRAMES-eng: 1048
         NUMBER_OF_BYTES : 38641
         NUMBER_OF_BYTES-eng: 38641
         _STATISTICS_WRITING_APP: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_APP-eng: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_DATE_UTC: 2018-01-23 22:07:33
         _STATISTICS_WRITING_DATE_UTC-eng: 2018-01-23 22:07:33
         _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
         _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
       Stream #0:4(eng): Subtitle: subrip
       Metadata:
         title           : Sub. Ingles
         BPS             : 72
         BPS-eng         : 72
         DURATION        : 01:32:29.880000000
         DURATION-eng    : 01:32:29.880000000
         NUMBER_OF_FRAMES: 1820
         NUMBER_OF_FRAMES-eng: 1820
         NUMBER_OF_BYTES : 50243
         NUMBER_OF_BYTES-eng: 50243
         _STATISTICS_WRITING_APP: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_APP-eng: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_DATE_UTC: 2018-01-23 22:07:33
         _STATISTICS_WRITING_DATE_UTC-eng: 2018-01-23 22:07:33
         _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
         _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
    File 'output.mp4' already exists. Overwrite ? [y/N] y
    [mp4 @ 000002935ee0ff00] track 1: codec frame size is not set
    Output #0, mp4, to 'output.mp4':
     Metadata:
       title           : claucha75
       encoder         : Lavf58.33.100
       Stream #0:0: Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 23.98 fps, 23.98 tbr, 16k tbn, 1k tbc (default)
       Metadata:
         title           : claucha75
         BPS             : 4146894
         BPS-eng         : 4146894
         DURATION        : 01:37:12.952000000
         DURATION-eng    : 01:37:12.952000000
         NUMBER_OF_FRAMES: 139851
         NUMBER_OF_FRAMES-eng: 139851
         NUMBER_OF_BYTES : 3023579528
         NUMBER_OF_BYTES-eng: 3023579528
         _STATISTICS_WRITING_APP: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_APP-eng: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_DATE_UTC: 2018-01-23 22:07:33
         _STATISTICS_WRITING_DATE_UTC-eng: 2018-01-23 22:07:33
         _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
         _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
       Stream #0:1(spa): Audio: ac3 (ac-3 / 0x332D6361), 48000 Hz, 5.1(side), fltp, 448 kb/s (default)
       Metadata:
         title           : Latino
         BPS             : 448000
         BPS-eng         : 448000
         DURATION        : 01:37:13.888000000
         DURATION-eng    : 01:37:13.888000000
         NUMBER_OF_FRAMES: 182309
         NUMBER_OF_FRAMES-eng: 182309
         NUMBER_OF_BYTES : 326697728
         NUMBER_OF_BYTES-eng: 326697728
         _STATISTICS_WRITING_APP: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_APP-eng: mkvmerge v20.0.0 ('I Am The Sun') 64-bit
         _STATISTICS_WRITING_DATE_UTC: 2018-01-23 22:07:33
         _STATISTICS_WRITING_DATE_UTC-eng: 2018-01-23 22:07:33
         _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
         _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
    Stream mapping:
     Stream #0:0 -> #0:0 (copy)
     Stream #0:1 -> #0:1 (copy)
    Press [q] to stop, [?] for help
    frame=139851 fps=2149 q=-1.0 Lsize= 3275868kB time=01:37:13.85 bitrate=4600.0kbits/s speed=89.7x
    video:2952714kB audio:319041kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.125715%

    The command produces a MP4 file. The file takes a long time to open and then it takes several more minutes for a frame to appear. The converted file is also missing audio.

    Does anyone have an idea about the slow loading time and missing audio ?