Excel file as an HTML table and Date formatting

If you create an Excel file using an HTML Table, then it exists a way to format the cells based on some CSS rules. Some examples can be found on this blog post.

I spent some time trying to figure out how to display correctly the dates, whatever your regional settings are ; for exemple in the USA the format is MM/dd/YYYY, and for the rest of the world is dd/MM/YYYY.

Finally I found that the content of the date cells must always be defined with the same format : YYY-MM-dd HH:mm, and then we can apply a style like mso-number-format:"dd\-mmm\-yyyy\ hh\:mm".

Example:

<html>
<head>
<style>br {mso-data-placement:same-cell} .xls-date {mso-number-format:"dd-mmm-yyyy hh:mm"}</style>
</head>
<body>
  <table>
    <tr>
      <th>Event Name</th>
      <th>Event Date</th>
    </tr>
    <tr>
      <td>Birthday Party</td>
      <td class="xls-date">2015-11-01 10:00</td>
    </tr>
  </table>
</html>

So the date cell will display: 01-Nov-2015 10:00 and will be interpreted as a Date cell by Excel.

Pure Javascript Drag and Drop cross browser from IE8

I was looking for a simple JavaScript to drag a div element around, and that would work with IE8 and without any third party libraries (like jQuery). It’s been very difficult to find a simple code !

Finally http://news.qooxdoo.org/mouse-capturing saved me with some code… but there was still a problem with IE8 due to the mouse that wasn’t losing capture. So after some research, I’ve been able to create a code that works for IE8 and modern browsers:

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <!-- `top` and `left` must be defined into the `style` -->
    <div id="popup" style="background-color:green;position:absolute;top:0px;left:0px;width:250px;height:250px;z-index:9999;box-shadow: 6px 6px 5px #888888;border-radius:6px;border:1px solid #4f4f4f;">
      <div id="popup_bar" style="width:100%;background-color:#aaff66;position:relative;top:0;border-radius:6px 6px 0 0; text-align:center;height:24px;cursor:move">Title</div>
      <p>Content of the popup</p>
    </div>
  </body>
<script>/* see below for the javascript */</script>
</html>
!function() {
  function addListener(element, type, callback, capture) {
    if (element.addEventListener) {
      element.addEventListener(type, callback, capture);
    } else {
      element.attachEvent("on" + type, callback);
    }
  }
  
  function draggable(element) {
    var dragging = null;
  
    addListener(element, "mousedown", function(e) {
      var e = window.event || e;
      dragging = {
        mouseX: e.clientX,
        mouseY: e.clientY,
        startX: parseInt(element.style.left),
        startY: parseInt(element.style.top)
      };
      if (element.setCapture) element.setCapture();
    });
  
    addListener(element, "losecapture", function() {
      dragging = null;
    });
  
    addListener(document, "mouseup", function() {
      dragging = null;
      if (document.releaseCapture) document.releaseCapture();
    }, true);
  
    var dragTarget = element.setCapture ? element : document;
  
    addListener(dragTarget, "mousemove", function(e) {
      if (!dragging) return;
  
      var e = window.event || e;
      var top = dragging.startY + (e.clientY - dragging.mouseY);
      var left = dragging.startX + (e.clientX - dragging.mouseX);
  
      element.style.top = (Math.max(0, top)) + "px";
      element.style.left = (Math.max(0, left)) + "px";
    }, true);
  };    
  
  // here you must define the element to be draggable
  draggable(document.getElementById("popup"));
}();

You can test this code with the demo or see it on Gist.

How to expand Sharepoint 2013 calendar by default [JavaScript]

This code has been tested for Sharepoint 2013 only. It permits to expand by default (so as soon as the page is loaded) the events in the Month calendar view.

See here a solution for Sharepoint 2010.

Tested with IE8 and Firefox 41. You’ll have to add the below JavaScript code into your calendar page:

// the below function simulate a click on a link
function fireEventClick(elem){
    if(document.createEvent){                                                 
      var e = document.createEvent('MouseEvents');
      e.initMouseEvent('click', /* Event type */
      true, /* Can bubble */
      true, /* Cancelable */
      document.defaultView, /* View */
      1, /* Mouse clicks */
      0, /* Screen x */
      0, /* Screen y */
      0, /* Client x */
      0, /* Client y */
      false, /* Ctrl */
      false, /* Alt */
      false, /* Shift */
      false, /* Meta */
      0, /* Button */
      null); /* Related target */
      elem.dispatchEvent(e);                     
    } else { // pour IE
      elem.click();
    }
}

// Expand the events
// because Sharepoint redraw ALL the events when we click on Expand, then we need a special recurrent function
function ExpandEvents(idx) {
  var a = document.querySelectorAll('a[evtid="expand_collapse"]');
  if (idx < a.length) {
    if (a[idx].parentNode.getAttribute("_expand") !== "collapse") fireEventClick(a[idx]);
    ExpandEvents(++idx);
  }
}

function onCalendarGridsRendered(){
  setTimeout(function() {
    ExpandEvents(0)
  }, 250)
}

// some code reused from http://www.codeproject.com/Tips/759006/Enhancing-SharePoint-Calendar-sp-ui-applicationpag
SP.SOD.executeOrDelayUntilScriptLoaded(function () {
    //Week or Day Calendar View
    SP.UI.ApplicationPages.DetailCalendarView.prototype.renderGrids_Old = SP.UI.ApplicationPages.DetailCalendarView.prototype.renderGrids;
    SP.UI.ApplicationPages.DetailCalendarView.prototype.renderGrids = function SP_UI_ApplicationPages_DetailCalendarView$renderGrids($p0) {
      this.renderGrids_Old($p0);
      onCalendarGridsRendered();
    };
    
    //Month Calendar View
    SP.UI.ApplicationPages.SummaryCalendarView.prototype.renderGrids_Old = SP.UI.ApplicationPages.SummaryCalendarView.prototype.renderGrids;
    SP.UI.ApplicationPages.SummaryCalendarView.prototype.renderGrids = function SP_UI_ApplicationPages_SummaryCalendarView$renderGrids($p0) {
      this.renderGrids_Old($p0);
      onCalendarGridsRendered();
    };
    
    ExpandEvents(0)
}, "SP.UI.ApplicationPages.Calendar.js");

And we can hide the « Collapse » links with one line of CSS:

.ms-cal-nav[evtid="expand_collapse"] { display: none !important }

Transform pseudo currency to number in JavaScript

In JavaScript I want to change some formatted numbers to a regular number.

The code might be look like that:

var aNb=[ 1500, "1,500", "15,00", "1,500,000", "1,500,000.25", "1000.25", "1 000 000"];
for (var i=0; i < aNb.length; i++) {
  var nb = aNb[i] + "";
  if (nb.split(",").length <= 2)
    nb = nb.replace(/,(\d{2})$/,".$1");
  nb = nb.replace(/[^\d\.\-]/g, '').replace(/\s/g,"")
  
  console.log(aNb[i], "=>", nb);
}

/* result:
1500 => 1500
1,500 => 1500
15,00 => 15.00
1,500,000 => 1500000
1,500,000.25 => 1500000.25
1000.25 => 1000.25
1 000 000 => 1000000
*/

Force CORS headers in Firefox to allow cross domain calls

This guy created a Firefox extension to force the CORS (access-control) headers from a call. This is very useful when you want to do a JavaScript/AJAX query over another website that doesn’t allow the cross domain calls.

His code is on github. I’ve the XPI compiled version on my blog (into a ZIP file) found from jo.se/f website.

You’ll need to add the addon bar (restored) in order to use ForceCORS.

Then you have to go to the about:config and search for forcecors.headers in order to set it up as you need. If it’s for an intranet with credentials required, then check my tip on github.

Make sure you have restarted Firefox and click on the cors that appears into the bottom addon bar of Firefox. It should switch to red. You can now do cross domain calls!

Sharepoint Workflow: Check if a field is empty [Sharepoint 2010]

The Sharepoint workflows are powerful but sometimes stupid…

If you want to:

  • Check if a Date Field is empty, then you can use a String Workflow Variable that contains your Date Field as a Short Date (SP2013) (or a String for SP2010), and then compare it to « 1/1/0001 » (or « 1/1/0001 12:00:00 AM » for SP2010)
  • Check if a Currency field is empty… you cannot because it returns 0 when empty, so you have to change it to a Number field…
  • Check if a Lookup field is empty, then set the Lookup field to a String variable and check if this variable is empty

« class-phpmailer out of memory using GuiForm » avec WordPress

Ayant un WordPress sur 1and1 j’ai été confronté à un « out of memory » sur le fichier class-phpmailer.php à cause d’un appel AJAX d’un formulaire créé avec GuiForm. Je ne peux pas faire grand chose côté serveur à cause de l’hébergement partagé… Donc j’ai fouillé comment contourner le problème.

Il va s’agir de modifier le fichier guiform/classes/GuiForm/Module/Ajax.php du plugin.

On va remplacer la fonction mailer() afin d’utiliser la fonction wp_mail fournie par WordPress. La fonction mailer() devient :

	public function mailer($type = 'mail', $init = array()){
		
		global $wpdb, $guiform;
		
		$subject = "";
		$MsgHTML = "";
    $headers = "";
    $attachments = "";
		$sendTo = array_map('trim', explode(',', $init['to']));
				
		$sendCc = array_map('trim', explode(',', $init['cc']));
		$sendBcc = array_map('trim', explode(',', $init['bcc']));
		$sendReplyTo = array_map('trim', explode(',', $init['reply-to']));
		
		/* Make sure the PHPMailer class has been instantiated 
		// (Re)create it, if it's gone missing
		if ( !is_object( $phpmailer ) || !is_a( $phpmailer, 'PHPMailer' ) ) {
			require_once ABSPATH . WPINC . '/class-phpmailer.php';
			require_once ABSPATH . WPINC . '/class-smtp.php';
			$phpmailer = new PHPMailer(true);
			$phpmailer->clearAllRecipients();
		  $phpmailer->SMTPAuth = true;
		}*/
		
		if($type == 'test-mail'){
			$data = $wpdb->get_row($wpdb->prepare("SELECT name, value FROM $wpdb->guiform_options WHERE id = %d", $this->_id));
		  $sendTo = array($data->name);
		  $row = unserialize($data->value);
		  $row = array_map('trim', $row);
			$html = "<strong>". __('Greetings!', GuiForm_Plugin::NAME) ."</strong><br /><br />";
			$html .=  __("This is a test message.", GuiForm_Plugin::NAME) ."<br /><br />";
			$MsgHTML = self::emailTpl($html);
			/*$phpmailer->SetFrom("noreply@guiform.com", GuiForm_Plugin::PACKAGE);
			$phpmailer->Subject = __('Test Message', GuiForm_Plugin::NAME);*/
      $headers .= 'From: noreply@guiform.com' . "\r\n";
      $subject = __('Test Message', GuiForm_Plugin::NAME);
		}
		else if($type == 'activation-mail'){
			$data = $wpdb->get_row($wpdb->prepare("SELECT name, value FROM $wpdb->guiform_options WHERE id = %d", $this->_id));
		  $row = unserialize($data->value);
		  $row = array_map('trim', $row);
		  $mv_code = md5(time());
			$row['key'] = $mv_code;
			$guiform->updateOption($data->name, $row, 'mail', $this->_id);
			//$phpmailer->Subject = __("Email Verification", GuiForm_Plugin::NAME);
      $subject = __("Email Verification", GuiForm_Plugin::NAME);
			$sendTo = array($data->name);
			$vlink = get_site_url() ."/?". $guiform->getOption('permalink')->value['value'] .'='. $this->_id ."&mv-code=$mv_code";
		
			$html = "Hello ".$row['name'].",<br /><br />";
			$html .= __("To enable this email address from sending emails with your forms we must first verify by clicking the link below:", GuiForm_Plugin::NAME) ."<br /><br />";
			$html .= __("Verification Link: ", GuiForm_Plugin::NAME) ."<a target=\"_blank\" href=\"$vlink\">". __("click here!", GuiForm_Plugin::NAME) ."</a><br /><br />";
			$MsgHTML = self::emailTpl($html);
			//$phpmailer->SetFrom("noreply@guiform.com", "GuiForm");
      $headers .= 'From: noreply@guiform.com' . "\r\n";
		}
		else if($type == 'mail'){	
			
			$init['message'] = str_replace("\\r\\n", "<br />", $init['message']);
			$init['message'] = stripcslashes($init['message']);
			
			//Do not remove &nbsp and <br />.
			$MsgHTML = $init['message'] ."   <br />";
			
			//$phpmailer->SetFrom($init['from'], "");
			//$phpmailer->Subject = $init['subject'];
      $headers .= 'Reply-To: '.$init['from'] . "\r\n";
      $headers .= 'From: '.$init['from'] . "\r\n";
      $subject = $init['subject'];
			
			if(sizeof($init['attachment'])){
				foreach($init['attachment'] as $file){
					//$phpmailer->AddAttachment(self::getAttachmentPath($file['url']), $file['name']);
          $attachments = self::getAttachmentPath($file['url']);
				}
			}
			
			if(sizeof($sendReplyTo)){
				foreach($sendReplyTo as $replyTo){
					if(is_email($replyTo)){
						//$phpmailer->AddReplyTo($replyTo);
            $headers .= 'Reply-To: '.$replyTo. "\r\n";
					}
				}
			}
			
			
			if(sizeof($sendCc)){
				foreach($sendCc as $mailCc){
					if(is_email($mailCc)){
				  	//$phpmailer->AddCC($mailCc);
            $headers .= 'Cc: '.$mailCc."\r\n";
					}
				}
			}
			
			if(sizeof($sendBcc)){
				foreach($sendBcc as $mailBcc){
					if(is_email($mailBcc)){
				  	//$phpmailer->AddCC($mailBcc);
            $headers .= 'Bcc: '.$mailBcc."\r\n";
					}
				}
			}
		}
		
		/*$phpmailer->Body = html_entity_decode($MsgHTML);
		$phpmailer->AltBody = strip_tags($MsgHTML);
		$phpmailer->IsHTML(true);
		$phpmailer->CharSet = "UTF-8";*/
    $headers .= 'MIME-Version: 1.0' . "\r\n";
    $headers .= 'Content-Type: text/html; charset=UTF-8'."\r\n";
    $body = html_entity_decode($MsgHTML);
		wp_mail( $sendTo, $subject, $body, $headers, $attachments);
/*
		foreach($sendTo as $mailTo){
			if($phpmailer->validateAddress($mailTo)){
				$phpmailer->AddAddress($mailTo);
			}
		}
		
		$smtpSettings = $guiform->getOption($this->form, false, 'smtp')->value;
		
		if($smtpSettings->smtp_enable){
			$row['protocol'] = 'smtp';
			$row['smtp_host'] = $smtpSettings->smtp_host;
			$row['smtp_port'] = $smtpSettings->smtp_port;
		}
		
		$phpmailer->Mailer = $row['protocol'];
		
		if($row['protocol'] == 'smtp'){
			$phpmailer->IsSMTP();
			$phpmailer->SMTPSecure = $row['smtp_encryption'];
			$phpmailer->Host       = $row['smtp_host'];
			$phpmailer->Port       = $row['smtp_port'];
		}
		
		if(filter_var($row['smtp_auth'], FILTER_VALIDATE_BOOLEAN)) {
			$phpmailer->SMTPAuth = true;
			$phpmailer->Username = trim($row['smtp_username']);
			$phpmailer->Password = trim($row['smtp_password']);
		}
		
    if(!$phpmailer->send()) {
			die( __("Mailer Error: ", GuiForm_Plugin::NAME) . $phpmailer->ErrorInfo);
		} else {
			$phpmailer->clearAllRecipients();
		  $phpmailer->clearAttachments();
			if($type !== 'mail'){
				die( __("Message sent! Please check your email for message.", GuiForm_Plugin::NAME));
			}
		}
*/
	}

Afficher correctement les caractères dans les fichiers de logs [Unix]

Lorsqu’on regarde ses fichiers de logs Apache (par exemple), on peut se retrouver face à des caractères dont l’encodage est bizarre… par exemple « là » donnera « l\xe0 ».

Pour afficher correctement les caractères dans votre console (en l’occurrence j’utilise Putty en encodage Latin1), il faut utiliser la commande suivante, trouvée sur StackOverflow :
tailf /var/log/apache2/error.log | while read -r line; do echo -e "$line"; done;

Windows 10 et Cortana : lancer les recherches sur Google au lieu de Bing sous Firefox

Microsoft essaie d’imposer son moteur de recherche, mais je continue à préférer Google…. Du coup quand Cortana sous Windows 10 nous redirige sur Bing, ça m’agace…

Sous Firefox on peut utiliser l’extension Redirector puis appliquer les règles suivantes :

  • Example URL : https://www.bing.com/search?q=*&*
  • Include Pattern : https://www.bing.com/search?q=*&*
  • Redirect To : https://www.google.de/#safe=off&q=$1
  • Pattern Type : Wildcard

Les recherches de Cortana se feront alors sous Google au lieu de Bing.

(via Reddit)

Android 5.1.1 system rw Operation not permitted

I was trying to update my Sony Xperia Z3 Compact from Android 5.0.2 (rooted) to Android 5.1.1, and everything worked well except that I got this issue : mount: Operation not permitted
when I was trying to put in write mode the system folder.

Also I tried SDFix and I got the error « Update failed, platform.xml file could not be updated ».

When I tried « ES Explorer », with Root Mode, I had SuperSU asking for root permission, but then « ES Explorer » said my system is not rooted.

After hours of digging I finally found I had to use that file discovered in that XDA thread. Just download it, unzip, then launch the install.bat