[gnome-shell/wip/fmuellner/notification-redux+sass: 98/122] calendar: Copy URLHightlighter and friends here
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/wip/fmuellner/notification-redux+sass: 98/122] calendar: Copy URLHightlighter and friends here
- Date: Tue, 17 Feb 2015 15:12:12 +0000 (UTC)
commit 0eb24dc3ad3c96364134af32336a707eaaecd188
Author: Florian Müllner <fmuellner gnome org>
Date: Mon Feb 16 19:40:00 2015 +0100
calendar: Copy URLHightlighter and friends here
js/ui/calendar.js | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 143 insertions(+), 0 deletions(-)
---
diff --git a/js/ui/calendar.js b/js/ui/calendar.js
index 97d2034..36ebe0a 100644
--- a/js/ui/calendar.js
+++ b/js/ui/calendar.js
@@ -11,6 +11,7 @@ const Signals = imports.signals;
const Pango = imports.gi.Pango;
const Gettext_gtk30 = imports.gettext.domain('gtk30');
const Mainloop = imports.mainloop;
+const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Layout = imports.ui.layout;
@@ -18,6 +19,7 @@ const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
+const Util = imports.misc.util;
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
const SHOW_WEEKDATE_KEY = 'show-weekdate';
@@ -874,6 +876,147 @@ const Notification = new Lang.Class({
});
Signals.addSignalMethods(Notification.prototype);
+function _fixMarkup(text, allowMarkup) {
+ if (allowMarkup) {
+ // Support &, ", ', < and >, escape all other
+ // occurrences of '&'.
+ let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&');
+
+ // Support <b>, <i>, and <u>, escape anything else
+ // so it displays as raw markup.
+ _text = _text.replace(/<(?!\/?[biu]>)/g, '<');
+
+ try {
+ Pango.parse_markup(_text, -1, '');
+ return _text;
+ } catch (e) {}
+ }
+
+ // !allowMarkup, or invalid markup
+ return GLib.markup_escape_text(text, -1);
+}
+
+const URLHighlighter = new Lang.Class({
+ Name: 'URLHighlighter',
+
+ _init: function(text, lineWrap, allowMarkup) {
+ if (!text)
+ text = '';
+ this.actor = new St.Label({ reactive: true, style_class: 'url-highlighter' });
+ this._linkColor = '#ccccff';
+ this.actor.connect('style-changed', Lang.bind(this, function() {
+ let [hasColor, color] = this.actor.get_theme_node().lookup_color('link-color', false);
+ if (hasColor) {
+ let linkColor = color.to_string().substr(0, 7);
+ if (linkColor != this._linkColor) {
+ this._linkColor = linkColor;
+ this._highlightUrls();
+ }
+ }
+ }));
+ this.actor.clutter_text.line_wrap = lineWrap;
+ this.actor.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
+
+ this.setMarkup(text, allowMarkup);
+ this.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
+ // Don't try to URL highlight when invisible.
+ // The MessageTray doesn't actually hide us, so
+ // we need to check for paint opacities as well.
+ if (!actor.visible || actor.get_paint_opacity() == 0)
+ return Clutter.EVENT_PROPAGATE;
+
+ // Keep Notification.actor from seeing this and taking
+ // a pointer grab, which would block our button-release-event
+ // handler, if an URL is clicked
+ return this._findUrlAtPos(event) != -1;
+ }));
+ this.actor.connect('button-release-event', Lang.bind(this, function (actor, event) {
+ if (!actor.visible || actor.get_paint_opacity() == 0)
+ return Clutter.EVENT_PROPAGATE;
+
+ let urlId = this._findUrlAtPos(event);
+ if (urlId != -1) {
+ let url = this._urls[urlId].url;
+ if (url.indexOf(':') == -1)
+ url = 'http://' + url;
+
+ Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1));
+ return Clutter.EVENT_STOP;
+ }
+ return Clutter.EVENT_PROPAGATE;
+ }));
+ this.actor.connect('motion-event', Lang.bind(this, function(actor, event) {
+ if (!actor.visible || actor.get_paint_opacity() == 0)
+ return Clutter.EVENT_PROPAGATE;
+
+ let urlId = this._findUrlAtPos(event);
+ if (urlId != -1 && !this._cursorChanged) {
+ global.screen.set_cursor(Meta.Cursor.POINTING_HAND);
+ this._cursorChanged = true;
+ } else if (urlId == -1) {
+ global.screen.set_cursor(Meta.Cursor.DEFAULT);
+ this._cursorChanged = false;
+ }
+ return Clutter.EVENT_PROPAGATE;
+ }));
+ this.actor.connect('leave-event', Lang.bind(this, function() {
+ if (!this.actor.visible || this.actor.get_paint_opacity() == 0)
+ return Clutter.EVENT_PROPAGATE;
+
+ if (this._cursorChanged) {
+ this._cursorChanged = false;
+ global.screen.set_cursor(Meta.Cursor.DEFAULT);
+ }
+ return Clutter.EVENT_PROPAGATE;
+ }));
+ },
+
+ setMarkup: function(text, allowMarkup) {
+ text = text ? _fixMarkup(text, allowMarkup) : '';
+ this._text = text;
+
+ this.actor.clutter_text.set_markup(text);
+ /* clutter_text.text contain text without markup */
+ this._urls = Util.findUrls(this.actor.clutter_text.text);
+ this._highlightUrls();
+ },
+
+ _highlightUrls: function() {
+ // text here contain markup
+ let urls = Util.findUrls(this._text);
+ let markup = '';
+ let pos = 0;
+ for (let i = 0; i < urls.length; i++) {
+ let url = urls[i];
+ let str = this._text.substr(pos, url.pos - pos);
+ markup += str + '<span foreground="' + this._linkColor + '"><u>' + url.url + '</u></span>';
+ pos = url.pos + url.url.length;
+ }
+ markup += this._text.substr(pos);
+ this.actor.clutter_text.set_markup(markup);
+ },
+
+ _findUrlAtPos: function(event) {
+ let success;
+ let [x, y] = event.get_coords();
+ [success, x, y] = this.actor.transform_stage_point(x, y);
+ let find_pos = -1;
+ for (let i = 0; i < this.actor.clutter_text.text.length; i++) {
+ let [success, px, py, line_height] = this.actor.clutter_text.position_to_coords(i);
+ if (py > y || py + line_height < y || x < px)
+ continue;
+ find_pos = i;
+ }
+ if (find_pos != -1) {
+ for (let i = 0; i < this._urls.length; i++)
+ if (find_pos >= this._urls[i].pos &&
+ this._urls[i].pos + this._urls[i].url.length > find_pos)
+ return i;
+ }
+ return -1;
+ }
+});
+
const Message = new Lang.Class({
Name: 'Message',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]