[california] Linkify event description: Bug #726846



commit a63abf547c141fbe6f823fb91921d20140964aaf
Author: Jim Nelson <jim yorba org>
Date:   Wed Jun 18 15:42:57 2014 -0700

    Linkify event description: Bug #726846

 src/Makefile.am                             |    2 +
 src/application/california-application.vala |    2 +
 src/host/host-show-event.vala               |   21 ++++++-
 src/util/util-markup.vala                   |   84 +++++++++++++++++++++++++++
 src/util/util.vala                          |   26 ++++++++
 5 files changed, 133 insertions(+), 2 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 2d87178..2b50cad 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -125,7 +125,9 @@ california_VALASOURCES = \
        toolkit/toolkit-popup.vala \
        toolkit/toolkit-stack-model.vala \
        \
+       util/util.vala \
        util/util-gfx.vala \
+       util/util-markup.vala \
        util/util-memory.vala \
        util/util-string.vala \
        util/util-uri.vala \
diff --git a/src/application/california-application.vala b/src/application/california-application.vala
index bab1a70..6d2405f 100644
--- a/src/application/california-application.vala
+++ b/src/application/california-application.vala
@@ -167,6 +167,7 @@ public class Application : Gtk.Application {
         
         // unit initialization
         try {
+            Util.init();
             Host.init();
             Manager.init();
             Activator.init();
@@ -188,6 +189,7 @@ public class Application : Gtk.Application {
         Activator.terminate();
         Manager.terminate();
         Host.terminate();
+        Util.terminate();
         
         base.shutdown();
     }
diff --git a/src/host/host-show-event.vala b/src/host/host-show-event.vala
index 39acd37..18d5200 100644
--- a/src/host/host-show-event.vala
+++ b/src/host/host-show-event.vala
@@ -80,7 +80,7 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
         set_label(when_label, when_text, event.get_event_time_pretty_string(Calendar.Timezone.local));
         
         // description
-        set_label(null, description_text, escape(event.description));
+        set_label(null, description_text, Markup.linkify(escape(event.description), linkify_delegate));
         
         // don't current support updating or removing recurring events properly; see
         // https://bugzilla.gnome.org/show_bug.cgi?id=725786
@@ -94,7 +94,24 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
     }
     
     private string? escape(string? plain) {
-        return !String.is_empty(plain) ? Markup.escape_text(plain) : plain;
+        return !String.is_empty(plain) ? GLib.Markup.escape_text(plain) : plain;
+    }
+    
+    private bool linkify_delegate(string uri, bool known_protocol, out string? pre_markup,
+        out string? post_markup) {
+        // preserve but don't linkify if unknown protocol
+        if (!known_protocol) {
+            pre_markup = null;
+            post_markup = null;
+            
+            return true;
+        }
+        
+        // anchor it
+        pre_markup = "<a href=\"%s\">".printf(uri);
+        post_markup = "</a>";
+        
+        return true;
     }
     
     // Note that text is not escaped, up to caller to determine if necessary or not.
diff --git a/src/util/util-markup.vala b/src/util/util-markup.vala
new file mode 100644
index 0000000..e633cf1
--- /dev/null
+++ b/src/util/util-markup.vala
@@ -0,0 +1,84 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+namespace California.Markup {
+
+/**
+ * Given a URI, return the prefix markup and the postfix markup as strings.
+ *
+ * known_protocol indicates the URI has a well-known protocol (i.e. http:// or ftp://, etc.)
+ *
+ * Returns false if the uri should not be included in the string returned by { link linkify}.  To
+ * leave a URI bare, return null for both strings and return true.
+ */
+public delegate bool LinkifyDelegate(string uri, bool known_protocol, out string? pre_markup,
+    out string? post_markup);
+
+// Regex to detect URLs.
+// Originally from http://daringfireball.net/2010/07/improved_regex_for_matching_urls
+private const string URL_REGEX = 
"(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’]))";
+
+// Regex to determine if a URL has a known protocol.
+private const string PROTOCOL_REGEX = 
"^(aim|apt|bitcoin|cvs|ed2k|ftp|file|finger|git|gtalk|http|https|irc|ircs|irc6|lastfm|ldap|ldaps|magnet|news|nntp|rsync|sftp|skype|smb|sms|svn|telnet|tftp|ssh|webcal|xmpp):";
+
+private Regex url_regex;
+private Regex protocol_regex;
+
+/**
+ * Called by Util.init()
+ */
+internal void init() throws Error {
+    url_regex = new Regex(URL_REGEX, RegexCompileFlags.CASELESS | RegexCompileFlags.OPTIMIZE);
+    protocol_regex = new Regex(PROTOCOL_REGEX, RegexCompileFlags.CASELESS | RegexCompileFlags.OPTIMIZE);
+}
+
+/**
+ * Called by Util.terminate()
+ */
+internal void terminate() {
+    url_regex = null;
+    protocol_regex = null;
+}
+
+/**
+ * Replace all the URIs in a string with link markup provided by { link LinkifyDelegate}.
+ *
+ * NOTE: linkify() is not thread-safe.
+ */
+public string? linkify(string? unlinked, LinkifyDelegate linkify_cb) {
+    if (String.is_empty(unlinked))
+        return unlinked;
+    
+    try {
+        return url_regex.replace_eval(unlinked, -1, 0, 0, (match_info, result) => {
+            // match zero is the only match we're interested in
+            string? url = match_info.fetch(0);
+            if (String.is_empty(url))
+                return false;
+            
+            // have original caller provide markup (or drop the URL)
+            string? pre_markup, post_markup;
+            if (!linkify_cb(url, protocol_regex.match(url), out pre_markup, out post_markup))
+                return false;
+            
+            // put it all together
+            result.append_printf("%s%s%s",
+                (pre_markup != null) ? pre_markup : "",
+                url,
+                (post_markup != null) ? post_markup : ""
+            );
+            
+            return false;
+        });
+    } catch (RegexError rerr) {
+        debug("Unable to linkify string: %s", rerr.message);
+        
+        return unlinked;
+    }
+}
+
+}
+
diff --git a/src/util/util.vala b/src/util/util.vala
new file mode 100644
index 0000000..8bc0b78
--- /dev/null
+++ b/src/util/util.vala
@@ -0,0 +1,26 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+namespace California.Util {
+
+private int init_count = 0;
+
+public void init() throws Error {
+    if (!Unit.do_init(ref init_count))
+        return;
+    
+    // internal init
+    Markup.init();
+}
+
+public void terminate() {
+    if (!Unit.do_terminate(ref init_count))
+        return;
+    
+    Markup.terminate();
+}
+
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]