aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README3
-rwxr-xr-xboot.php8
-rw-r--r--[-rwxr-xr-x]doc/Groups-and-Privacy.md2
-rwxr-xr-xinclude/api.php68
-rwxr-xr-xinclude/bb2diaspora.php41
-rwxr-xr-xinclude/bbcode.php72
-rwxr-xr-xinclude/diaspora.php26
-rwxr-xr-xinclude/html2bbcode.php397
-rwxr-xr-xinclude/items.php5
-rwxr-xr-xinclude/poller.php25
-rwxr-xr-xinclude/text.php26
-rw-r--r--[-rwxr-xr-x]library/markdown.php884
-rwxr-xr-xmod/group.php2
-rw-r--r--mod/notify.php10
-rwxr-xr-xmod/wall_upload.php22
-rwxr-xr-xview/de/friend_complete_eml.tpl2
-rwxr-xr-xview/de/intro_complete_eml.tpl2
-rwxr-xr-xview/de/lostpass_eml.tpl2
-rwxr-xr-xview/de/passchanged_eml.tpl2
-rwxr-xr-xview/de/register_open_eml.tpl2
-rwxr-xr-xview/de/request_notify_eml.tpl2
-rwxr-xr-xview/theme/vier/calendar.pngbin0 -> 3779 bytes
-rw-r--r--view/theme/vier/style.css478
23 files changed, 1377 insertions, 704 deletions
diff --git a/README b/README
new file mode 100644
index 000000000..e75d6319b
--- /dev/null
+++ b/README
@@ -0,0 +1,3 @@
+This is my personal fork of https://github.com/friendica/friendica
+
+If you want to have a stable version of friendica please look there.
diff --git a/boot.php b/boot.php
index 79a925961..8b78c0ee5 100755
--- a/boot.php
+++ b/boot.php
@@ -9,7 +9,7 @@ require_once('include/nav.php');
require_once('include/cache.php');
define ( 'FRIENDICA_PLATFORM', 'Friendica');
-define ( 'FRIENDICA_VERSION', '2.3.1259' );
+define ( 'FRIENDICA_VERSION', '2.3.1260' );
define ( 'DFRN_PROTOCOL_VERSION', '2.22' );
define ( 'DB_UPDATE_VERSION', 1123 );
@@ -309,8 +309,12 @@ class App {
. 'library/phpsec' . PATH_SEPARATOR
. '.' );
- if((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'],0,2) === "q=")
+ if((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'],0,2) === "q=") {
$this->query_string = substr($_SERVER['QUERY_STRING'],2);
+ // removing trailing / - maybe a nginx problem
+ if (substr($this->query_string, 0, 1) == "/")
+ $this->query_string = substr($this->query_string, 1);
+ }
if(x($_GET,'q'))
$this->cmd = trim($_GET['q'],'/\\');
diff --git a/doc/Groups-and-Privacy.md b/doc/Groups-and-Privacy.md
index 61da25a21..7e93fb9d0 100755..100644
--- a/doc/Groups-and-Privacy.md
+++ b/doc/Groups-and-Privacy.md
@@ -22,7 +22,7 @@ But wait, there's more...
If you look carefully when visiting a group from your Network page, the lock icon under the status update box has an exclamation mark next to it. This is meant to draw attention to that lock. Click the lock. You will see that since you are only viewing a certain group of people, your status updates while on that screen default to only being seen by that same group of people. This is how you keep your future employers from seeing what you write to your drinking buddies. You can over-ride this setting, but this makes it easy to separate your conversations into different friend circles.
-These private conversations work best when your friends are Freindika members. We know who else can see the conversations - nobody, *unless* your friends cut and paste the messages and send them to others.
+These private conversations work best when your friends are Friendica members. We know who else can see the conversations - nobody, *unless* your friends cut and paste the messages and send them to others.
This is a trust issue you need to be aware of. No software in the world can prevent your friends from leaking your confidential and trusted communications. Only a wise choice of friends.
diff --git a/include/api.php b/include/api.php
index 04f95ebd9..013f4b97a 100755
--- a/include/api.php
+++ b/include/api.php
@@ -99,6 +99,10 @@
**************************/
function api_call(&$a){
GLOBAL $API, $called_api;
+
+ // preset
+ $type="json";
+
foreach ($API as $p=>$info){
if (strpos($a->query_string, $p)===0){
$called_api= explode("/",$p);
@@ -109,14 +113,14 @@
load_contact_links(local_user());
- logger('API call for ' . $a->user['username'] . ': ' . $a->query_string);
+ logger('API call for ' . $a->user['username'] . ': ' . $a->query_string);
logger('API parameters: ' . print_r($_REQUEST,true));
- $type="json";
+ $type="json";
if (strpos($a->query_string, ".xml")>0) $type="xml";
if (strpos($a->query_string, ".json")>0) $type="json";
if (strpos($a->query_string, ".rss")>0) $type="rss";
- if (strpos($a->query_string, ".atom")>0) $type="atom";
-
+ if (strpos($a->query_string, ".atom")>0) $type="atom";
+
$r = call_user_func($info['func'], $a, $type);
if ($r===false) return;
@@ -126,8 +130,8 @@
header ("Content-Type: text/xml");
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
- case "json":
- //header ("Content-Type: application/json");
+ case "json":
+ //header ("Content-Type: application/json");
foreach($r as $rr)
return json_encode($rr);
break;
@@ -139,19 +143,20 @@
header ("Content-Type: application/atom+xml");
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
-
+
}
//echo "<pre>"; var_dump($r); die();
}
}
+ logger('API call not implemented: '.$a->query_string." - ".print_r($_REQUEST,true));
$r = '<status><error>not implemented</error></status>';
switch($type){
case "xml":
header ("Content-Type: text/xml");
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
- case "json":
- header ("Content-Type: application/json");
+ case "json":
+ header ("Content-Type: application/json");
return json_encode(array('error' => 'not implemented'));
break;
case "rss":
@@ -162,7 +167,6 @@
header ("Content-Type: application/atom+xml");
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
-
}
}
@@ -453,7 +457,49 @@
return null;
}
- // TODO - media uploads
+/*Waitman Gobble Mod*/
+ function api_statuses_mediap(&$a, $type) {
+ if (local_user()===false) {
+ logger('api_statuses_update: no user');
+ return false;
+ }
+ $user_info = api_get_user($a);
+
+ $_REQUEST['type'] = 'wall';
+ $_REQUEST['profile_uid'] = local_user();
+ $_REQUEST['api_source'] = true;
+ $txt = urldecode(requestdata('status'));
+
+ require_once('library/HTMLPurifier.auto.php');
+ require_once('include/html2bbcode.php');
+
+ if((strpos($txt,'<') !== false) || (strpos($txt,'>') !== false)) {
+ $txt = html2bb_video($txt);
+ $config = HTMLPurifier_Config::createDefault();
+ $config->set('Cache.DefinitionImpl', null);
+ $purifier = new HTMLPurifier($config);
+ $txt = $purifier->purify($txt);
+ }
+ $txt = html2bbcode($txt);
+
+ $a->argv[1]=$user_info['screen_name']; //should be set to username?
+
+ $_REQUEST['hush']='yeah'; //tell wall_upload function to return img info instead of echo
+ require_once('mod/wall_upload.php');
+ $bebop = wall_upload_post($a);
+
+ //now that we have the img url in bbcode we can add it to the status and insert the wall item.
+ $_REQUEST['body']=$txt."\n\n".$bebop;
+ require_once('mod/item.php');
+ item_post($a);
+
+ // this should output the last post (the one we just posted).
+ return api_status_show($a,$type);
+ }
+ api_register_func('api/statuses/mediap','api_statuses_mediap', true);
+/*Waitman Gobble Mod*/
+
+
function api_statuses_update(&$a, $type) {
if (local_user()===false) {
logger('api_statuses_update: no user');
diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php
index c26b0c334..70d4bec9a 100755
--- a/include/bb2diaspora.php
+++ b/include/bb2diaspora.php
@@ -8,35 +8,54 @@ require_once('include/html2bbcode.php');
// we don't want to support a bbcode specific markdown interpreter
// and the markdown library we have is pretty good, but provides HTML output.
-// So we'll use that to convert to HTML, then convert the HTML back to bbcode,
+// So we'll use that to convert to HTML, then convert the HTML back to bbcode,
// and then clean up a few Diaspora specific constructs.
function diaspora2bb($s) {
+ // for testing purposes: Collect raw markdown articles
+ $file = tempnam("/tmp/friendica/", "markdown");
+ file_put_contents($file, $s);
+
$s = html_entity_decode($s,ENT_COMPAT,'UTF-8');
- $s = str_replace("\r","\n",$s);
+
+ // Too many new lines. So deactivated the following line
+ // $s = str_replace("\r","\n",$s);
+ // Simply remove cr.
+ $s = str_replace("\r","",$s);
+
+ // <br/> is invalid. Replace it with the valid expression
+ $s = str_replace("<br/>","<br />",$s);
$s = preg_replace('/\@\{(.+?)\; (.+?)\@(.+?)\}/','@[url=https://$3/u/$2]$1[/url]',$s);
- $s = preg_replace('/\#([^\s\#])/','\\#$1',$s);
+ // Escaping the hash tags - doesn't always seem to work
+ // $s = preg_replace('/\#([^\s\#])/','\\#$1',$s);
+ // This seems to work
+ $s = preg_replace('/\#([^\s\#])/','&#35;$1',$s);
$s = Markdown($s);
- $s = str_replace('&#35;','#',$s);
- $s = str_replace("\n",'<br />',$s);
+ $s = str_replace('&#35;','#',$s);
+
+ $s = str_replace("\n",'<br />',$s);
$s = html2bbcode($s);
// $s = str_replace('&#42;','*',$s);
+ // Convert everything that looks like a link to a link
+ $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3]$2$3[/url]',$s);
- $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/url\]/ism",'[youtube]$2[/youtube]',$s);
- $s = preg_replace("/\[url\=https?:\/\/www.youtube.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism",'[youtube]$1[/youtube]',$s);
- $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/url\]/ism",'[vimeo]$2[/vimeo]',$s);
- $s = preg_replace("/\[url\=https?:\/\/vimeo.com\/([0-9]+)\](.*?)\[\/url\]/ism",'[vimeo]$1[/vimeo]',$s);
- $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url]$2$3$4[/url]',$s);
+ //$s = preg_replace("/([^\]\=]|^)(https?\:\/\/)(vimeo|youtu|www\.youtube|soundcloud)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3$4]$2$3$4[/url]',$s);
+ $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/url\]/ism",'[youtube]$2[/youtube]',$s);
+ $s = preg_replace("/\[url\=https?:\/\/www.youtube.com\/watch\?v\=(.*?)\].*?\[\/url\]/ism",'[youtube]$1[/youtube]',$s);
+ $s = preg_replace("/\[url\=?(.*?)\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/url\]/ism",'[vimeo]$2[/vimeo]',$s);
+ $s = preg_replace("/\[url\=https?:\/\/vimeo.com\/([0-9]+)\](.*?)\[\/url\]/ism",'[vimeo]$1[/vimeo]',$s);
// remove duplicate adjacent code tags
$s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism","[code]$2[/code]", $s);
- $s = scale_diaspora_images($s);
+
+ // Don't show link to full picture (until it is fixed)
+ $s = scale_diaspora_images($s, false);
return $s;
}
diff --git a/include/bbcode.php b/include/bbcode.php
index cae867eb8..32053b4ec 100755
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -12,20 +12,20 @@ function stripcode_br_cb($s) {
function tryoembed($match){
$url = ((count($match)==2)?$match[1]:$match[2]);
// logger("tryoembed: $url");
-
+
$o = oembed_fetch_url($url);
//echo "<pre>"; var_dump($match, $url, $o); killme();
if ($o->type=="error") return $match[0];
-
+
$html = oembed_format_object($o);
return $html; //oembed_iframe($html,$o->width,$o->height);
-
+
}
-// [noparse][i]italic[/i][/noparse] turns into
-// [noparse][ i ]italic[ /i ][/noparse],
+// [noparse][i]italic[/i][/noparse] turns into
+// [noparse][ i ]italic[ /i ][/noparse],
// to hide them from parser.
function bb_spacefy($st) {
@@ -36,7 +36,7 @@ function bb_spacefy($st) {
return $new_str;
}
-// The previously spacefied [noparse][ i ]italic[ /i ][/noparse],
+// The previously spacefied [noparse][ i ]italic[ /i ][/noparse],
// now turns back and the [noparse] tags are trimed
// returning [i]italic[/i]
@@ -59,8 +59,8 @@ function bbcode($Text,$preserve_nl = false) {
$Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_spacefy',$Text);
- // Extract a single private image which uses data url's since preg has issues with
- // large data sizes. Stash it away while we do bbcode conversion, and then put it back
+ // Extract a single private image which uses data url's since preg has issues with
+ // large data sizes. Stash it away while we do bbcode conversion, and then put it back
// in after we've done all the regex matching. We cannot use any preg functions to do this.
$saved_image = '';
@@ -71,13 +71,13 @@ function bbcode($Text,$preserve_nl = false) {
$start_fragment = substr($Text,0,$img_start);
$img_start += strlen('[img]');
$saved_image = substr($Text,$img_start,$img_end - $img_start);
- $end_fragment = substr($Text,$img_end + strlen('[/img]'));
+ $end_fragment = substr($Text,$img_end + strlen('[/img]'));
// logger('saved_image: ' . $saved_image,LOGGER_DEBUG);
$Text = $start_fragment . '[$#saved_image#$]' . $end_fragment;
}
// If we find any event code, turn it into an event.
- // After we're finished processing the bbcode we'll
+ // After we're finished processing the bbcode we'll
// replace all of the event code with a reformatted version.
$ev = bbtoevent($Text);
@@ -105,7 +105,7 @@ function bbcode($Text,$preserve_nl = false) {
// Perform URL Search
$Text = preg_replace("/([^\]\=]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1<a href="$2" target="external-link">$2</a>', $Text);
-
+
$Text = preg_replace_callback("/\[bookmark\=([^\]]*)\].*?\[\/bookmark\]/ism",'tryoembed',$Text);
$Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",'[url=$1]$2[/url]',$Text);
@@ -118,7 +118,7 @@ function bbcode($Text,$preserve_nl = false) {
// Perform MAIL Search
$Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '<a href="mailto:$1">$1</a>', $Text);
$Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '<a href="mailto:$1">$2</a>', $Text);
-
+
// Check for bold text
$Text = preg_replace("(\[b\](.*?)\[\/b\])ism",'<strong>$1</strong>',$Text);
@@ -149,21 +149,20 @@ function bbcode($Text,$preserve_nl = false) {
$Text = str_replace("[*]", "<li>", $Text);
$Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '<li>$1</li>' ,$Text);
- $Text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '<ul class="listbullet" style="list-style-type: circle;">$1</ul>' ,$Text);
- $Text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '<ul class="listbullet" style="list-style-type: circle;">$1</ul>'
-,$Text);
- $Text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '<ul class="listnone" style="list-style-type: none;">$1</ul>' ,$Text);
- $Text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '<ul class="listdecimal" style="list-style-type: decimal;">$1</ul>' ,$Text);
- $Text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '<ul class="listdecimal" style="list-style-type: decimal;">$1</ul>'
-,$Text);
- $Text = preg_replace("/\[list=((?-i)i)\](.*?)\[\/list\]/ism",'<ul class="listlowerroman" style="list-style-type:
-lower-roman;">$2</ul>' ,$Text);
- $Text = preg_replace("/\[list=((?-i)I)\](.*?)\[\/list\]/ism", '<ul class="listupperroman" style="list-style-type:
-upper-roman;">$2</ul>' ,$Text);
- $Text = preg_replace("/\[list=((?-i)a)\](.*?)\[\/list\]/ism", '<ul class="listloweralpha" style="list-style-type:
-lower-alpha;">$2</ul>' ,$Text);
- $Text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '<ul class="listupperalpha" style="list-style-type:
-upper-alpha;">$2</ul>' ,$Text);
+ // handle nested lists
+ $endlessloop = 0;
+ while (strpos($Text, "[/list]") and strpos($Text, "[list") and (++$endlessloop < 20)) {
+ $Text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '<ul class="listbullet" style="list-style-type: circle;">$1</ul>' ,$Text);
+ $Text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '<ul class="listnone" style="list-style-type: none;">$1</ul>' ,$Text);
+ $Text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '<ul class="listdecimal" style="list-style-type: decimal;">$1</ul>' ,$Text);
+ $Text = preg_replace("/\[list=((?-i)i)\](.*?)\[\/list\]/ism",'<ul class="listlowerroman" style="list-style-type: lower-roman;">$2</ul>' ,$Text);
+ $Text = preg_replace("/\[list=((?-i)I)\](.*?)\[\/list\]/ism", '<ul class="listupperroman" style="list-style-type: upper-roman;">$2</ul>' ,$Text);
+ $Text = preg_replace("/\[list=((?-i)a)\](.*?)\[\/list\]/ism", '<ul class="listloweralpha" style="list-style-type: lower-alpha;">$2</ul>' ,$Text);
+ $Text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '<ul class="listupperalpha" style="list-style-type: upper-alpha;">$2</ul>' ,$Text);
+ }
+
+ $Text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '<ul class="listbullet" style="list-style-type: circle;">$1</ul>' ,$Text);
+ $Text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '<ul class="listdecimal" style="list-style-type: decimal;">$1</ul>' ,$Text);
$Text = preg_replace("/\[th\](.*?)\[\/th\]/sm", '<th>$1</th>' ,$Text);
$Text = preg_replace("/\[td\](.*?)\[\/td\]/sm", '<td>$1</td>' ,$Text);
@@ -190,21 +189,24 @@ upper-alpha;">$2</ul>' ,$Text);
// Check for [code] text
$Text = preg_replace("/\[code\](.*?)\[\/code\]/ism","$CodeLayout", $Text);
-
-
-
// Declare the format for [quote] layout
- $QuoteLayout = '<blockquote>$1</blockquote>';
+ $QuoteLayout = '<blockquote>$1</blockquote>';
// Check for [quote] text
- $Text = preg_replace("/\[quote\](.*?)\[\/quote\]/ism","$QuoteLayout", $Text);
+ // handle nested quotes
+ $endlessloop = 0;
+ while (strpos($Text, "[/quote]") !== false and strpos($Text, "[quote]") !== false and (++$endlessloop < 20))
+ $Text = preg_replace("/\[quote\](.*?)\[\/quote\]/ism","$QuoteLayout", $Text);
// Check for [quote=Author] text
$t_wrote = t('$1 wrote:');
- $Text = preg_replace("/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism",
- "<blockquote><strong>" . $t_wrote . "</strong> $2</blockquote>",
- $Text);
+ // handle nested quotes
+ $endlessloop = 0;
+ while (strpos($Text, "[/quote]") !== false and strpos($Text, "[quote=") !== false and (++$endlessloop < 20))
+ $Text = preg_replace("/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism",
+ "<blockquote><strong>" . $t_wrote . "</strong> $2</blockquote>",
+ $Text);
// [img=widthxheight]image source[/img]
$Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '<img src="$3" style="height: $2px; width: $1px;" >', $Text);
diff --git a/include/diaspora.php b/include/diaspora.php
index a8e02e509..92f3500f2 100755
--- a/include/diaspora.php
+++ b/include/diaspora.php
@@ -451,7 +451,7 @@ function diaspora_request($importer,$xml) {
// perhaps we were already sharing with this person. Now they're sharing with us.
// That makes us friends.
- if($contact['rel'] == CONTACT_IS_FOLLOWER) {
+ if($contact['rel'] == CONTACT_IS_FOLLOWER && $importer['page-flags'] != PAGE_COMMUNITY) {
q("UPDATE `contact` SET `rel` = %d, `writable` = 1 WHERE `id` = %d AND `uid` = %d LIMIT 1",
intval(CONTACT_IS_FRIEND),
intval($contact['id']),
@@ -619,6 +619,18 @@ function diaspora_request($importer,$xml) {
return;
}
+function diaspora_post_allow($importer,$contact) {
+ if(($contact['blocked']) || ($contact['readonly']))
+ return false;
+ if($contact['rel'] == CONTACT_IS_SHARING || $contact['rel'] == CONTACT_IS_FRIEND)
+ return true;
+ if($contact['rel'] == CONTACT_IS_FOLLOWER)
+ if($importer['page-flags'] == PAGE_COMMUNITY)
+ return true;
+ return false;
+}
+
+
function diaspora_post($importer,$xml) {
$a = get_app();
@@ -629,7 +641,7 @@ function diaspora_post($importer,$xml) {
if(! $contact)
return;
- if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
+ if(! diaspora_post_allow($importer,$contact)) {
logger('diaspora_post: Ignoring this author.');
return 202;
}
@@ -748,7 +760,7 @@ function diaspora_reshare($importer,$xml) {
if(! $contact)
return;
- if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
+ if(! diaspora_post_allow($importer,$contact)) {
logger('diaspora_reshare: Ignoring this author: ' . $diaspora_handle . ' ' . print_r($xml,true));
return 202;
}
@@ -900,7 +912,7 @@ function diaspora_asphoto($importer,$xml) {
if(! $contact)
return;
- if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
+ if(! diaspora_post_allow($importer,$contact)) {
logger('diaspora_asphoto: Ignoring this author.');
return 202;
}
@@ -1001,7 +1013,7 @@ function diaspora_comment($importer,$xml,$msg) {
return;
}
- if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
+ if(! diaspora_post_allow($importer,$contact)) {
logger('diaspora_comment: Ignoring this author.');
return 202;
}
@@ -1446,7 +1458,7 @@ function diaspora_photo($importer,$xml,$msg) {
return;
}
- if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
+ if(! diaspora_post_allow($importer,$contact)) {
logger('diaspora_photo: Ignoring this author.');
return 202;
}
@@ -1503,7 +1515,7 @@ function diaspora_like($importer,$xml,$msg) {
return;
}
- if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) {
+ if(! diaspora_post_allow($importer,$contact)) {
logger('diaspora_like: Ignoring this author.');
return 202;
}
diff --git a/include/html2bbcode.php b/include/html2bbcode.php
index 8025c336b..4297ff2f9 100755
--- a/include/html2bbcode.php
+++ b/include/html2bbcode.php
@@ -1,127 +1,286 @@
<?php
+/*
+html2bbcode.php
+Converter for HTML to BBCode
+Made by: ike@piratenpartei.de
+Originally made for the syncom project: http://wiki.piratenpartei.de/Syncom
+ https://github.com/annando/Syncom
+*/
-/**
- * html2bbcode
- */
-
-
-function html2bbcode($s) {
-
-
- // only keep newlines from source that are within pre tags
-
- $s = stripnl_exceptinpre($s);
-
-
- // Tags to Find
-
- $htmltags = array(
- '/\<pre\>(.*?)\<\/pre\>/is',
- '/\<p(.*?)\>/is',
- '/\<\/p\>/is',
- '/\<b\>(.*?)\<\/b\>/is',
- '/\<i\>(.*?)\<\/i\>/is',
- '/\<u\>(.*?)\<\/u\>/is',
- '/\<ul\>(.*?)\<\/ul\>/is',
- '/\<li\>(.*?)\<\/li\>/is',
- '/\<img(.*?)width: *([0-9]+)(.*?)height: *([0-9]+)(.*?)src=\"(.*?)\" (.*?)\>/is',
- '/\<img(.*?)height: *([0-9]+)(.*?)width: *([0-9]+)(.*?)src=\"(.*?)\" (.*?)\>/is',
- '/\<img(.*?)src=\"(.*?)\"(.*?)width: *([0-9]+)(.*?)height: *([0-9]+)(.*?)\>/is',
- '/\<img(.*?)src=\"(.*?)\"(.*?)height: *([0-9]+)(.*?)width: *([0-9]+)(.*?)\>/is',
- '/\<img(.*?) src=\"(.*?)\" (.*?)\>/is',
- '/\<div(.*?)\>(.*?)\<\/div\>/is',
- '/\<br(.*?)\>/is',
- '/\<strong\>(.*?)\<\/strong\>/is',
- '/\<a (.*?)href=\"(.*?)\"(.*?)\>(.*?)\<\/a\>/is',
- '/\<code\>(.*?)\<\/code\>/is',
- '/\<span style=\"color:(.*?)\"\>(.*?)\<\/span\>/is',
- '/\<span style=\"font-size:(.*?)\"\>(.*?)\<\/span\>/is',
- '/\<blockquote\>(.*?)\<\/blockquote\>/is',
- '/\<video(.*?) src=\"(.*?)\" (.*?)\>(.*?)\<\/video\>/is',
- '/\<audio(.*?) src=\"(.*?)\" (.*?)\>(.*?)\<\/audio\>/is',
- '/\<iframe(.*?) src=\"(.*?)\" (.*?)\>(.*?)\<\/iframe\>/is',
-
- );
-
- // Replace with
-
- $bbtags = array(
- '[code]$1[/code]',
- '',
- "\n",
- '[b]$1[/b]',
- '[i]$1[/i]',
- '[u]$1[/u]',
- '[list]$1[/list]',
- '[*]$1',
- '[img=$2x$4]$6[/img]',
- '[img=$4x$2]$6[/img]',
- '[img=$4x$6]$2[/img]',
- '[img=$6x$4]$2[/img]',
- '[img]$2[/img]',
- '$2',
- "\n",
- '[b]$1[/b]',
- '[url=$2]$4[/url]',
- '[code]$1[/code]',
- '[color="$1"]$2[/color]',
- '[size=$1]$2[/size]',
- '[quote]$1[/quote]',
- '[video]$1[/video]',
- '[audio]$1[/audio]',
- '[iframe]$1[/iframe]',
- );
-
- // Replace $htmltags in $text with $bbtags
- $text = preg_replace ($htmltags, $bbtags, $s);
-
- call_hooks('html2bbcode', $text);
-
- // Strip all other HTML tags
- $text = strip_tags($text);
- return $text;
+function node2bbcode(&$doc, $oldnode, $attributes, $startbb, $endbb)
+{
+ do {
+ $done = node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb);
+ } while ($done);
+}
+
+function node2bbcodesub(&$doc, $oldnode, $attributes, $startbb, $endbb)
+{
+ $savestart = str_replace('$', '%', $startbb);
+ $replace = false;
+
+ $xpath = new DomXPath($doc);
+
+ $list = $xpath->query("//".$oldnode);
+ foreach ($list as $oldNode) {
+
+ $attr = array();
+ if ($oldNode->attributes->length)
+ foreach ($oldNode->attributes as $attribute)
+ $attr[$attribute->name] = $attribute->value;
+
+ $replace = true;
+
+ $startbb = $savestart;
+
+ $i = 0;
+
+ foreach ($attributes as $attribute => $value) {
+
+ $startbb = str_replace('%'.++$i, '$1', $startbb);
+
+ if (strpos('*'.$startbb, '$1') > 0) {
+
+ if ($replace and (@$attr[$attribute] != '')) {
+
+ $startbb = preg_replace($value, $startbb, $attr[$attribute], -1, $count);
+
+ // If nothing could be changed
+ if ($count == 0)
+ $replace = false;
+ } else
+ $replace = false;
+ } else {
+ if (@$attr[$attribute] != $value)
+ $replace = false;
+ }
+ }
+
+ if ($replace) {
+ $StartCode = $oldNode->ownerDocument->createTextNode($startbb);
+ $EndCode = $oldNode->ownerDocument->createTextNode($endbb);
+
+ $oldNode->parentNode->insertBefore($StartCode, $oldNode);
+ if ($oldNode->hasChildNodes()) {
+ foreach ($oldNode->childNodes as $child) {
+ $newNode = $child->cloneNode(true);
+ $oldNode->parentNode->insertBefore($newNode, $oldNode);
+ }
+ }
+
+ $oldNode->parentNode->insertBefore($EndCode, $oldNode);
+ $oldNode->parentNode->removeChild($oldNode);
+ }
+ }
+ return($replace);
}
-function stripnl_exceptinpre($string)
+function deletenode(&$doc, $node)
{
- // First, check for <pre> tag
- if(strpos($string, '<pre>') === false)
- {
- return str_replace("\n","", $string);
- }
-
- // If there is a <pre>, we have to split by line
- // and manually replace the linebreaks
-
- $strArr=explode("\n", $string);
-
- $output="";
- $preFound=false;
-
- // Loop over each line
- foreach($strArr as $line)
- { // See if the line has a <pre>. If it does, set $preFound to true
- if(strpos($line, "<pre>") !== false)
- {
- $preFound=true;
- }
- elseif(strpos($line, "</pre>") !== false)
- {
- $preFound=false;
- }
-
- // If we are in a pre tag, add line and also add \n, else add the line without \n
- if($preFound)
- {
- $output .= $line . "\n";
- }
- else
- {
- $output .= $line ;
- }
- }
-
- return $output;
+ $xpath = new DomXPath($doc);
+ $list = $xpath->query("//".$node);
+ foreach ($list as $child)
+ $child->parentNode->removeChild($child);
}
+function html2bbcode($message)
+{
+
+ //$file = tempnam("/tmp/", "html");
+ //file_put_contents($file, $message);
+
+ $message = str_replace("\r", "", $message);
+
+ $message = str_replace(array(
+ "<li><p>",
+ "</p></li>"),
+ array(
+ "<li>",
+ "</li>"),
+ $message);
+
+ // remove namespaces
+ $message = preg_replace('=<(\w+):(.+?)>=', '<removeme>', $message);
+ $message = preg_replace('=</(\w+):(.+?)>=', '</removeme>', $message);
+
+ $doc = new DOMDocument();
+ $doc->preserveWhiteSpace = false;
+
+ $message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8");
+
+ @$doc->loadHTML($message);
+
+ deletenode($doc, 'style');
+ deletenode($doc, 'head');
+ deletenode($doc, 'title');
+ deletenode($doc, 'meta');
+ deletenode($doc, 'xml');
+ deletenode($doc, 'removeme');
+
+ $xpath = new DomXPath($doc);
+ $list = $xpath->query("//pre");
+ foreach ($list as $node)
+ $node->nodeValue = str_replace("\n", "\r", $node->nodeValue);
+
+ $message = $doc->saveHTML();
+ $message = str_replace(array("\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"), array("<", ">", "<br>", " ", ""), $message);
+ $message = preg_replace('= [\s]*=i', " ", $message);
+ @$doc->loadHTML($message);
+
+ node2bbcode($doc, 'html', array(), "", "");
+ node2bbcode($doc, 'body', array(), "", "");
+
+ // Outlook-Quote - Variant 1
+ node2bbcode($doc, 'p', array('class'=>'MsoNormal', 'style'=>'margin-left:35.4pt'), '[quote]', '[/quote]');
+
+ // Outlook-Quote - Variant 2
+ node2bbcode($doc, 'div', array('style'=>'border:none;border-left:solid blue 1.5pt;padding:0cm 0cm 0cm 4.0pt'), '[quote]', '[/quote]');
+
+ // MyBB-Stuff
+ node2bbcode($doc, 'span', array('style'=>'text-decoration: underline;'), '[u]', '[/u]');
+ node2bbcode($doc, 'span', array('style'=>'font-style: italic;'), '[i]', '[/i]');
+ node2bbcode($doc, 'span', array('style'=>'font-weight: bold;'), '[b]', '[/b]');
+
+ node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[font=$1][size=$2][color=$3]', '[/color][/size][/font]');
+ node2bbcode($doc, 'font', array('size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[size=$1][color=$2]', '[/color][/size]');
+ node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(.+)/'), '[font=$1][size=$2]', '[/size][/font]');
+ node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/', 'color'=>'/(.+)/'), '[font=$1][color=$3]', '[/color][/font]');
+ node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/'), '[font=$1]', '[/font]');
+ node2bbcode($doc, 'font', array('size'=>'/(\d+)/'), '[size=$1]', '[/size]');
+ node2bbcode($doc, 'font', array('color'=>'/(.+)/'), '[color=$1]', '[/color]');
+
+ node2bbcode($doc, 'span', array('style'=>'/.*color:\s*(.+?)[,;].*/'), '[color="$1"]', '[/color]');
+ node2bbcode($doc, 'span', array('style'=>'/.*font-size:\s*(\d+)/'), '[size=$1]', '[/size]');
+
+ //node2bbcode($doc, 'span', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]');
+ //node2bbcode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)pt.*/'), '[font=$1][size=$2]', '[/size][/font]');
+ //node2bbcode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)px.*/'), '[font=$1][size=$2]', '[/size][/font]');
+ //node2bbcode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]');
+
+ node2bbcode($doc, 'strong', array(), '[b]', '[/b]');
+ node2bbcode($doc, 'em', array(), '[i]', '[/i]');
+ node2bbcode($doc, 'b', array(), '[b]', '[/b]');
+ node2bbcode($doc, 'i', array(), '[i]', '[/i]');
+ node2bbcode($doc, 'u', array(), '[u]', '[/u]');
+
+ node2bbcode($doc, 'big', array(), "[size=large]", "[/size]");
+ node2bbcode($doc, 'small', array(), "[size=small]", "[/size]");
+
+ node2bbcode($doc, 'blockquote', array(), '[quote]', '[/quote]');
+
+ node2bbcode($doc, 'br', array(), "\n", '');
+
+ node2bbcode($doc, 'p', array('class'=>'MsoNormal'), "\n", "");
+ node2bbcode($doc, 'div', array('class'=>'MsoNormal'), "\r", "");
+
+ node2bbcode($doc, 'span', array(), "", "");
+
+ node2bbcode($doc, 'span', array(), "", "");
+ node2bbcode($doc, 'pre', array(), "", "");
+ node2bbcode($doc, 'div', array(), "\r", "\r");
+ node2bbcode($doc, 'p', array(), "\n", "\n");
+
+ node2bbcode($doc, 'ul', array(), "[list]", "[/list]");
+ node2bbcode($doc, 'ol', array(), "[list=1]", "[/list]");
+ node2bbcode($doc, 'li', array(), "[*]", "");
+
+ node2bbcode($doc, 'hr', array(), "[hr]", "");
+
+ //node2bbcode($doc, 'table', array(), "", "");
+ //node2bbcode($doc, 'tr', array(), "\n", "");
+ //node2bbcode($doc, 'td', array(), "\t", "");
+ node2bbcode($doc, 'table', array(), "[table]", "[/table]");
+ node2bbcode($doc, 'th', array(), "[th]", "[/th]");
+ node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
+ node2bbcode($doc, 'td', array(), "[td]", "[/td]");
+
+ node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n");
+ node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n");
+ node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n");
+ node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n");
+ node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n");
+ node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n");
+
+ node2bbcode($doc, 'a', array('href'=>'/(.+)/'), '[url=$1]', '[/url]');
+
+ node2bbcode($doc, 'img', array('src'=>'/(.+)/', 'width'=>'/(\d+)/', 'height'=>'/(\d+)/'), '[img$2x$3]$1', '[/img]');
+ node2bbcode($doc, 'img', array('src'=>'/(.+)/'), '[img]$1', '[/img]');
+
+
+ node2bbcode($doc, 'video', array('src'=>'/(.+)/'), '[video]$1', '[/video]');
+ node2bbcode($doc, 'audio', array('src'=>'/(.+)/'), '[audio]$1', '[/audio]');
+ node2bbcode($doc, 'iframe', array('src'=>'/(.+)/'), '[iframe]$1', '[/iframe]');
+
+ node2bbcode($doc, 'code', array(), '[code]$1', '[/code]');
+
+ $message = $doc->saveHTML();
+
+ // I'm removing something really disturbing
+ // Don't know exactly what it is
+ $message = str_replace(chr(194).chr(160), ' ', $message);
+
+ $message = str_replace("&nbsp;", " ", $message);
+
+ // removing multiple DIVs
+ $message = preg_replace('=\r *\r=i', "\n", $message);
+ $message = str_replace("\r", "\n", $message);
+
+ call_hooks('html2bbcode', $message);
+
+ $message = strip_tags($message);
+
+ $message = html_entity_decode($message, ENT_QUOTES, 'UTF-8');
+
+ $message = str_replace(array("<"), array("&lt;"), $message);
+
+ // remove quotes if they don't make sense
+ $message = preg_replace('=\[/quote\][\s]*\[quote\]=i', "\n", $message);
+
+ $message = preg_replace('=\[quote\]\s*=i', "[quote]", $message);
+ $message = preg_replace('=\s*\[/quote\]=i', "[/quote]", $message);
+
+ do {
+ $oldmessage = $message;
+ $message = str_replace("\n \n", "\n\n", $message);
+ } while ($oldmessage != $message);
+
+ do {
+ $oldmessage = $message;
+ $message = str_replace("\n\n\n", "\n\n", $message);
+ } while ($oldmessage != $message);
+
+ do {
+ $oldmessage = $message;
+ $message = str_replace(array(
+ "[/size]\n\n",
+ "\n[hr]",
+ "[hr]\n",
+ "\n[list",
+ "[/list]\n",
+ "\n[/list]",
+ "[list]\n",
+ "[list=1]\n",
+ "\n[*]"),
+ array(
+ "[/size]\n",
+ "[hr]",
+ "[hr]",
+ "[list",
+ "[/list]",
+ "[/list]",
+ "[list]",
+ "[list=1]",
+ "[*]"),
+ $message);
+ } while ($message != $oldmessage);
+
+ $message = str_replace(array('[b][b]', '[/b][/b]', '[i][i]', '[/i][/i]'),
+ array('[b]', '[/b]', '[i]', '[/i]'), $message);
+
+ // Handling Yahoo style of mails
+ $message = str_replace('[hr][b]From:[/b]', '[quote][b]From:[/b]', $message);
+
+ return(trim($message));
+}
+?>
diff --git a/include/items.php b/include/items.php
index 3db56da5f..347826042 100755
--- a/include/items.php
+++ b/include/items.php
@@ -1551,8 +1551,9 @@ function consume_feed($xml,$importer,&$contact, &$hub, $datedir = 0, $pass = 0)
}
$force_parent = false;
- if($contact['network'] === NETWORK_OSTATUS) {
- $force_parent = true;
+ if($contact['network'] === NETWORK_OSTATUS || stristr($contact['url'],'twitter.com')) {
+ if($contact['network'] === NETWORK_OSTATUS)
+ $force_parent = true;
if(strlen($datarray['title']))
unset($datarray['title']);
$r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d",
diff --git a/include/poller.php b/include/poller.php
index 3e10533b3..3e7a1e9b4 100755
--- a/include/poller.php
+++ b/include/poller.php
@@ -371,10 +371,14 @@ function poller_run($argv, $argc){
}
elseif($contact['network'] === NETWORK_MAIL || $contact['network'] === NETWORK_MAIL2) {
+ logger("Mail: Fetching");
+
$mail_disabled = ((function_exists('imap_open') && (! get_config('system','imap_disabled'))) ? 0 : 1);
if($mail_disabled)
continue;
+ logger("Mail: Enabled");
+
$mbox = null;
$x = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1",
intval($importer_uid)
@@ -388,6 +392,7 @@ function poller_run($argv, $argc){
openssl_private_decrypt(hex2bin($mailconf[0]['pass']),$password,$x[0]['prvkey']);
$mbox = email_connect($mailbox,$mailconf[0]['user'],$password);
unset($password);
+ logger("Mail: Connect");
if($mbox) {
q("UPDATE `mailacct` SET `last_check` = '%s' WHERE `id` = %d AND `uid` = %d LIMIT 1",
dbesc(datetime_convert()),
@@ -397,11 +402,16 @@ function poller_run($argv, $argc){
}
}
if($mbox) {
+ logger("Mail: mbox");
$msgs = email_poll($mbox,$contact['addr']);
if(count($msgs)) {
+ logger("Mail: Parsing ".count($msgs)." mails.");
+
foreach($msgs as $msg_uid) {
+ logger("Mail: Parsing mail ".$msg_uid);
+
$datarray = array();
$meta = email_msg_meta($mbox,$msg_uid);
$headers = email_msg_headers($mbox,$msg_uid);
@@ -436,23 +446,28 @@ function poller_run($argv, $argc){
);
if(count($r)) {
+ logger("Mail: Seen before ".$msg_uid);
if($meta->deleted && ! $r[0]['deleted']) {
q("UPDATE `item` SET `deleted` = 1, `changed` = '%s' WHERE `id` = %d LIMIT 1",
dbesc(datetime_convert()),
intval($r[0]['id'])
);
- }
+ }
continue;
}
$datarray['title'] = notags(trim($meta->subject));
$datarray['created'] = datetime_convert('UTC','UTC',$meta->date);
-
+
$r = email_get_msg($mbox,$msg_uid);
- if(! $r)
+ if(! $r) {
+ logger("Mail: can't fetch msg ".$msg_uid);
continue;
+ }
$datarray['body'] = escape_tags($r['body']);
- // some mailing lists have the original author as 'from' - add this sender info to msg body.
+ logger("Mail: Importing ".$msg_uid);
+
+ // some mailing lists have the original author as 'from' - add this sender info to msg body.
// todo: adding a gravatar for the original author would be cool
if(! stristr($meta->from,$contact['addr']))
@@ -469,7 +484,7 @@ function poller_run($argv, $argc){
$datarray['author-name'] = $contact['name'];
$datarray['author-link'] = 'mailbox';
$datarray['author-avatar'] = $contact['photo'];
-
+
$stored_item = item_store($datarray);
q("UPDATE `item` SET `last-child` = 0 WHERE `parent-uri` = '%s' AND `uid` = %d",
dbesc($datarray['parent-uri']),
diff --git a/include/text.php b/include/text.php
index 5ef870fd7..0f7d2f731 100755
--- a/include/text.php
+++ b/include/text.php
@@ -675,12 +675,24 @@ function linkify($s) {
* @Parameter: string $s
*
* Returns string
+ *
+ * It is expected that this function will be called using HTML text.
+ * We will escape text between HTML pre and code blocks from being
+ * processed.
+ *
+ * At a higher level, the bbcode [nosmile] tag can be used to prevent this
+ * function from being executed by the prepare_text() routine when preparing
+ * bbcode source for HTML display
+ *
*/
if(! function_exists('smilies')) {
function smilies($s, $sample = false) {
$a = get_app();
+ $s = preg_replace_callback('/<pre>(.*?)<\/pre>/ism','smile_encode',$s);
+ $s = preg_replace_callback('/<code>(.*?)<\/code>/ism','smile_encode',$s);
+
$texts = array(
'&lt;3',
'&lt;/3',
@@ -777,10 +789,24 @@ function smilies($s, $sample = false) {
$s = str_replace($params['texts'],$params['icons'],$params['string']);
}
+ $s = preg_replace_callback('/<pre>(.*?)<\/pre>/ism','smile_decode',$s);
+ $s = preg_replace_callback('/<code>(.*?)<\/code>/ism','smile_decode',$s);
+
return $s;
}}
+function smile_encode($m) {
+ return(str_replace($m[1],base64url_encode($m[1]),$m[0]));
+}
+
+function smile_decode($m) {
+ return(str_replace($m[1],base64url_decode($m[1]),$m[0]));
+}
+
+
+
+
if(! function_exists('day_translate')) {
function day_translate($s) {
$ret = str_replace(array('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'),
diff --git a/library/markdown.php b/library/markdown.php
index 343153186..f548fc26c 100755..100644
--- a/library/markdown.php
+++ b/library/markdown.php
@@ -3,17 +3,17 @@
# Markdown Extra - A text-to-HTML conversion tool for web writers
#
# PHP Markdown & Extra
-# Copyright (c) 2004-2008 Michel Fortin
-# <http://www.michelf.com/projects/php-markdown/>
+# Copyright (c) 2004-2012 Michel Fortin
+# <http://michelf.com/projects/php-markdown/>
#
# Original Markdown
-# Copyright (c) 2004-2006 John Gruber
+# Copyright (c) 2004-2006 John Gruber
# <http://daringfireball.net/projects/markdown/>
#
-define( 'MARKDOWN_VERSION', "1.0.1m" ); # Sat 21 Jun 2008
-define( 'MARKDOWNEXTRA_VERSION', "1.2.3" ); # Wed 31 Dec 2008
+define( 'MARKDOWN_VERSION', "1.0.1o" ); # Sun 8 Jan 2012
+define( 'MARKDOWNEXTRA_VERSION', "1.2.5" ); # Sun 8 Jan 2012
#
@@ -34,17 +34,6 @@ define( 'MARKDOWNEXTRA_VERSION', "1.2.3" ); # Wed 31 Dec 2008
@define( 'MARKDOWN_FN_LINK_CLASS', "" );
@define( 'MARKDOWN_FN_BACKLINK_CLASS', "" );
-# Enables special handling for links pointing outside of the current domain.
-@define( 'MARKDOWN_EL_ENABLE', true); # Use this feature at all?
-@define( 'MARKDOWN_EL_LOCAL_DOMAIN', null); # Leave as null to autodetect
-@define( 'MARKDOWN_EL_NEW_WINDOW', true); # Open link in a new browser?
-@define( 'MARKDOWN_EL_CSS_CLASS', 'external'); # Leave as null for no class
-
-# Enables header auto-self-linking.
-@define( 'MARKDOWN_HA_ENABLE', true ); # Use this feature at all?
-@define( 'MARKDOWN_HA_CLASS', 'hidden-selflink' ); # Leave as null for no class
-@define( 'MARKDOWN_HA_TEXT', '&larr;' ); # The text to use as the link
-
#
# WordPress settings:
@@ -80,17 +69,17 @@ function Markdown($text) {
/*
Plugin Name: Markdown Extra
-Plugin URI: http://www.michelf.com/projects/php-markdown/
-Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a>
-Version: 1.2.2
+Plugin URI: http://michelf.com/projects/php-markdown/
+Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>
+Version: 1.2.5
Author: Michel Fortin
-Author URI: http://www.michelf.com/
+Author URI: http://michelf.com/
*/
if (isset($wp_version)) {
# More details about how it works here:
- # <http://www.michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
-
+ # <http://michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
+
# Post content and excerpts
# - Remove WordPress paragraph generator.
# - Run Markdown on excerpt, then remove all tags.
@@ -105,13 +94,13 @@ if (isset($wp_version)) {
add_filter('get_the_excerpt', 'trim', 7);
add_filter('the_excerpt', 'mdwp_add_p');
add_filter('the_excerpt_rss', 'mdwp_strip_p');
-
+
remove_filter('content_save_pre', 'balanceTags', 50);
remove_filter('excerpt_save_pre', 'balanceTags', 50);
add_filter('the_content', 'balanceTags', 50);
add_filter('get_the_excerpt', 'balanceTags', 9);
}
-
+
# Add a footnote id prefix to posts when inside a loop.
function mdwp_MarkdownPost($text) {
static $parser;
@@ -126,7 +115,7 @@ if (isset($wp_version)) {
}
return $parser->transform($text);
}
-
+
# Comments
# - Remove WordPress paragraph generator.
# - Remove WordPress auto-link generator.
@@ -141,7 +130,7 @@ if (isset($wp_version)) {
add_filter('get_comment_text', 'Markdown', 6);
add_filter('get_comment_excerpt', 'Markdown', 6);
add_filter('get_comment_excerpt', 'mdwp_strip_p', 7);
-
+
global $mdwp_hidden_tags, $mdwp_placeholders;
$mdwp_hidden_tags = explode(' ',
'<p> </p> <pre> </pre> <ol> </ol> <ul> </ul> <li> </li>');
@@ -149,7 +138,7 @@ if (isset($wp_version)) {
'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '.
'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli'));
}
-
+
function mdwp_add_p($text) {
if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) {
$text = '<p>'.$text.'</p>';
@@ -157,7 +146,7 @@ if (isset($wp_version)) {
}
return $text;
}
-
+
function mdwp_strip_p($t) { return preg_replace('{</?p>}i', '', $t); }
function mdwp_hide_tags($text) {
@@ -182,7 +171,7 @@ function identify_modifier_markdown() {
'authors' => 'Michel Fortin and John Gruber',
'licence' => 'GPL',
'version' => MARKDOWNEXTRA_VERSION,
- 'help' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a>',
+ 'help' => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://michelf.com/projects/php-markdown/">More...</a>',
);
}
@@ -229,7 +218,7 @@ class Markdown_Parser {
# Needed to insert a maximum bracked depth while converting to PHP.
var $nested_brackets_depth = 6;
var $nested_brackets_re;
-
+
var $nested_url_parenthesis_depth = 4;
var $nested_url_parenthesis_re;
@@ -240,11 +229,11 @@ class Markdown_Parser {
# Change to ">" for HTML output.
var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
var $tab_width = MARKDOWN_TAB_WIDTH;
-
+
# Change to `true` to disallow markup or entities.
var $no_markup = false;
var $no_entities = false;
-
+
# Predefined urls and titles for reference links and images.
var $predef_urls = array();
var $predef_titles = array();
@@ -256,17 +245,17 @@ class Markdown_Parser {
#
$this->_initDetab();
$this->prepareItalicsAndBold();
-
- $this->nested_brackets_re =
+
+ $this->nested_brackets_re =
str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
str_repeat('\])*', $this->nested_brackets_depth);
-
- $this->nested_url_parenthesis_re =
+
+ $this->nested_url_parenthesis_re =
str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
-
+
$this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
-
+
# Sort document, block, and span gamut in ascendent priority order.
asort($this->document_gamut);
asort($this->block_gamut);
@@ -278,27 +267,27 @@ class Markdown_Parser {
var $urls = array();
var $titles = array();
var $html_hashes = array();
-
+
# Status flag to avoid invalid nesting.
var $in_anchor = false;
-
-
+
+
function setup() {
#
- # Called before the transformation process starts to setup parser
+ # Called before the transformation process starts to setup parser
# states.
#
# Clear global hashes.
$this->urls = $this->predef_urls;
$this->titles = $this->predef_titles;
$this->html_hashes = array();
-
+
$in_anchor = false;
}
-
+
function teardown() {
#
- # Called after the transformation process to clear any variable
+ # Called after the transformation process to clear any variable
# which may be taking up memory unnecessarly.
#
$this->urls = array();
@@ -313,7 +302,7 @@ class Markdown_Parser {
# and pass it through the document gamut.
#
$this->setup();
-
+
# Remove UTF-8 BOM and marker character in input, if present.
$text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
@@ -340,16 +329,16 @@ class Markdown_Parser {
foreach ($this->document_gamut as $method => $priority) {
$text = $this->$method($text);
}
-
+
$this->teardown();
return $text . "\n";
}
-
+
var $document_gamut = array(
# Strip link definitions, store in hashes.
"stripLinkDefinitions" => 20,
-
+
"runBasicBlockGamut" => 30,
);
@@ -367,14 +356,18 @@ class Markdown_Parser {
[ ]*
\n? # maybe *one* newline
[ ]*
- <?(\S+?)>? # url = $2
+ (?:
+ <(.+?)> # url = $2
+ |
+ (\S+?) # url = $3
+ )
[ ]*
\n? # maybe one newline
[ ]*
(?:
(?<=\s) # lookbehind for whitespace
["(]
- (.*?) # title = $3
+ (.*?) # title = $4
[")]
[ ]*
)? # title is optional
@@ -386,8 +379,9 @@ class Markdown_Parser {
}
function _stripLinkDefinitions_callback($matches) {
$link_id = strtolower($matches[1]);
- $this->urls[$link_id] = $matches[2];
- $this->titles[$link_id] =& $matches[3];
+ $url = $matches[2] == '' ? $matches[3] : $matches[2];
+ $this->urls[$link_id] = $url;
+ $this->titles[$link_id] =& $matches[4];
return ''; # String that will replace the block
}
@@ -405,14 +399,14 @@ class Markdown_Parser {
# hard-coded:
#
# * List "a" is made of tags which can be both inline or block-level.
- # These will be treated block-level when the start tag is alone on
- # its line, otherwise they're not matched here and will be taken as
+ # These will be treated block-level when the start tag is alone on
+ # its line, otherwise they're not matched here and will be taken as
# inline later.
# * List "b" is made of tags which are always block-level;
#
$block_tags_a_re = 'ins|del';
$block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
- 'script|noscript|form|fieldset|iframe|math|textarea';
+ 'script|noscript|form|fieldset|iframe|math';
# Regular expression for the content of a block tag.
$nested_tags_level = 4;
@@ -428,7 +422,7 @@ class Markdown_Parser {
|
\'[^\']*\' # text inside single quotes (tolerate ">")
)*
- )?
+ )?
';
$content =
str_repeat('
@@ -445,7 +439,7 @@ class Markdown_Parser {
str_repeat('
</\2\s*> # closing nested tag
)
- |
+ |
<(?!/\2\s*> # other tags with a different name
)
)*',
@@ -471,9 +465,9 @@ class Markdown_Parser {
)
( # save in $1
- # Match from `\n<tag>` to `</tag>\n`, handling nested tags
+ # Match from `\n<tag>` to `</tag>\n`, handling nested tags
# in between.
-
+
[ ]{0,'.$less_than_tab.'}
<('.$block_tags_b_re.')# start tag = $2
'.$attr.'> # attributes followed by > and \n
@@ -491,28 +485,28 @@ class Markdown_Parser {
</\3> # the matching end tag
[ ]* # trailing spaces/tabs
(?=\n+|\Z) # followed by a newline or end of document
-
- | # Special case just for <hr />. It was easier to make a special
+
+ | # Special case just for <hr />. It was easier to make a special
# case than to make the other regex more complicated.
-
+
[ ]{0,'.$less_than_tab.'}
<(hr) # start tag = $2
'.$attr.' # attributes
/?> # the matching end tag
[ ]*
(?=\n{2,}|\Z) # followed by a blank line or end of document
-
+
| # Special case for standalone HTML comments:
-
+
[ ]{0,'.$less_than_tab.'}
(?s:
<!-- .*? -->
)
[ ]*
(?=\n{2,}|\Z) # followed by a blank line or end of document
-
+
| # PHP and ASP-style processor instructions (<? and <%)
-
+
[ ]{0,'.$less_than_tab.'}
(?s:
<([?%]) # $2
@@ -521,7 +515,7 @@ class Markdown_Parser {
)
[ ]*
(?=\n{2,}|\Z) # followed by a blank line or end of document
-
+
)
)}Sxmi',
array(&$this, '_hashHTMLBlocks_callback'),
@@ -534,11 +528,11 @@ class Markdown_Parser {
$key = $this->hashBlock($text);
return "\n\n$key\n\n";
}
-
-
+
+
function hashPart($text, $boundary = 'X') {
#
- # Called whenever a tag must be hashed when a function insert an atomic
+ # Called whenever a tag must be hashed when a function insert an atomic
# element in the text stream. Passing $text to through this function gives
# a unique text-token which will be reverted back when calling unhash.
#
@@ -550,7 +544,7 @@ class Markdown_Parser {
# Swap back any tag hash found in $text so we do not have to `unhash`
# multiple times at the end.
$text = $this->unhash($text);
-
+
# Then hash the block.
static $i = 0;
$key = "$boundary\x1A" . ++$i . $boundary;
@@ -574,7 +568,7 @@ class Markdown_Parser {
#
"doHeaders" => 10,
"doHorizontalRules" => 20,
-
+
"doLists" => 40,
"doCodeBlocks" => 50,
"doBlockQuotes" => 60,
@@ -584,33 +578,33 @@ class Markdown_Parser {
#
# Run block gamut tranformations.
#
- # We need to escape raw HTML in Markdown source before doing anything
- # else. This need to be done for each block, and not only at the
+ # We need to escape raw HTML in Markdown source before doing anything
+ # else. This need to be done for each block, and not only at the
# begining in the Markdown function since hashed blocks can be part of
- # list items and could have been indented. Indented blocks would have
+ # list items and could have been indented. Indented blocks would have
# been seen as a code block in a previous pass of hashHTMLBlocks.
$text = $this->hashHTMLBlocks($text);
-
+
return $this->runBasicBlockGamut($text);
}
-
+
function runBasicBlockGamut($text) {
#
- # Run block gamut tranformations, without hashing HTML blocks. This is
+ # Run block gamut tranformations, without hashing HTML blocks. This is
# useful when HTML blocks are known to be already hashed, like in the first
# whole-document pass.
#
foreach ($this->block_gamut as $method => $priority) {
$text = $this->$method($text);
}
-
+
# Finally form paragraph and restore hashed blocks.
$text = $this->formParagraphs($text);
return $text;
}
-
-
+
+
function doHorizontalRules($text) {
# Do Horizontal Rules:
return preg_replace(
@@ -624,7 +618,7 @@ class Markdown_Parser {
[ ]* # Tailing spaces
$ # End of line.
}mx',
- "\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n",
+ "\n".$this->hashBlock("<hr$this->empty_element_suffix")."\n",
$text);
}
@@ -642,7 +636,7 @@ class Markdown_Parser {
# because ![foo][f] looks like an anchor.
"doImages" => 10,
"doAnchors" => 20,
-
+
# Make links out of things like `<http://example.com/>`
# Must come after doAnchors, because you can use < and >
# delimiters in inline links like [this](<url>).
@@ -663,11 +657,11 @@ class Markdown_Parser {
return $text;
}
-
-
+
+
function doHardBreaks($text) {
# Do hard breaks:
- return preg_replace_callback('/ {2,}\n/',
+ return preg_replace_callback('/ {2,}\n/',
array(&$this, '_doHardBreaks_callback'), $text);
}
function _doHardBreaks_callback($matches) {
@@ -681,7 +675,7 @@ class Markdown_Parser {
#
if ($this->in_anchor) return $text;
$this->in_anchor = true;
-
+
#
# First, handle reference-style links: [link text] [id]
#
@@ -710,37 +704,37 @@ class Markdown_Parser {
('.$this->nested_brackets_re.') # link text = $2
\]
\( # literal paren
- [ ]*
+ [ \n]*
(?:
- <(\S*)> # href = $3
+ <(.+?)> # href = $3
|
('.$this->nested_url_parenthesis_re.') # href = $4
)
- [ ]*
+ [ \n]*
( # $5
([\'"]) # quote char = $6
(.*?) # Title = $7
\6 # matching quote
- [ ]* # ignore any spaces/tabs between closing quote and )
+ [ \n]* # ignore any spaces/tabs between closing quote and )
)? # title is optional
\)
)
}xs',
- array(&$this, '_DoAnchors_inline_callback'), $text);
+ array(&$this, '_doAnchors_inline_callback'), $text);
#
# Last, handle reference-style shortcuts: [link text]
- # These must come last in case you've also got [link test][1]
- # or [link test](/foo)
+ # These must come last in case you've also got [link text][1]
+ # or [link text](/foo)
#
-// $text = preg_replace_callback('{
-// ( # wrap whole match in $1
-// \[
-// ([^\[\]]+) # link text = $2; can\'t contain [ or ]
-// \]
-// )
-// }xs',
-// array(&$this, '_doAnchors_reference_callback'), $text);
+ $text = preg_replace_callback('{
+ ( # wrap whole match in $1
+ \[
+ ([^\[\]]+) # link text = $2; can\'t contain [ or ]
+ \]
+ )
+ }xs',
+ array(&$this, '_doAnchors_reference_callback'), $text);
$this->in_anchor = false;
return $text;
@@ -754,7 +748,7 @@ class Markdown_Parser {
# for shortcut links like [this][] or [this].
$link_id = $link_text;
}
-
+
# lower-case and turn embedded newlines into spaces
$link_id = strtolower($link_id);
$link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
@@ -762,14 +756,14 @@ class Markdown_Parser {
if (isset($this->urls[$link_id])) {
$url = $this->urls[$link_id];
$url = $this->encodeAttribute($url);
-
+
$result = "<a href=\"$url\"";
if ( isset( $this->titles[$link_id] ) ) {
$title = $this->titles[$link_id];
$title = $this->encodeAttribute($title);
$result .= " title=\"$title\"";
}
-
+
$link_text = $this->runSpanGamut($link_text);
$result .= ">$link_text</a>";
$result = $this->hashPart($result);
@@ -792,7 +786,7 @@ class Markdown_Parser {
$title = $this->encodeAttribute($title);
$result .= " title=\"$title\"";
}
-
+
$link_text = $this->runSpanGamut($link_text);
$result .= ">$link_text</a>";
@@ -821,7 +815,7 @@ class Markdown_Parser {
\]
)
- }xs',
+ }xs',
array(&$this, '_doImages_reference_callback'), $text);
#
@@ -835,18 +829,18 @@ class Markdown_Parser {
\]
\s? # One optional whitespace character
\( # literal paren
- [ ]*
+ [ \n]*
(?:
<(\S*)> # src url = $3
|
('.$this->nested_url_parenthesis_re.') # src url = $4
)
- [ ]*
+ [ \n]*
( # $5
([\'"]) # quote char = $6
(.*?) # title = $7
\6 # matching quote
- [ ]*
+ [ \n]*
)? # title is optional
\)
)
@@ -906,7 +900,7 @@ class Markdown_Parser {
# Setext-style headers:
# Header 1
# ========
- #
+ #
# Header 2
# --------
#
@@ -936,7 +930,7 @@ class Markdown_Parser {
# Terrible hack to check we haven't found an empty list item.
if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
return $matches[0];
-
+
$level = $matches[2]{0} == '=' ? 1 : 2;
$block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
return "\n" . $this->hashBlock($block) . "\n\n";
@@ -956,22 +950,25 @@ class Markdown_Parser {
# Re-usable patterns to match list item bullets and number markers:
$marker_ul_re = '[*+-]';
- $marker_ol_re = '\d+[.]';
+ $marker_ol_re = '\d+[\.]';
$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
- $markers_relist = array($marker_ul_re, $marker_ol_re);
+ $markers_relist = array(
+ $marker_ul_re => $marker_ol_re,
+ $marker_ol_re => $marker_ul_re,
+ );
- foreach ($markers_relist as $marker_re) {
+ foreach ($markers_relist as $marker_re => $other_marker_re) {
# Re-usable pattern to match any entirel ul or ol list:
$whole_list_re = '
( # $1 = whole list
( # $2
- [ ]{0,'.$less_than_tab.'}
- ('.$marker_re.') # $3 = first list item marker
+ ([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces
+ ('.$marker_re.') # $4 = first list item marker
[ ]+
)
(?s:.+?)
- ( # $4
+ ( # $5
\z
|
\n{2,}
@@ -980,13 +977,19 @@ class Markdown_Parser {
[ ]*
'.$marker_re.'[ ]+
)
+ |
+ (?= # Lookahead for another kind of list
+ \n
+ \3 # Must have the same indentation
+ '.$other_marker_re.'[ ]+
+ )
)
)
'; // mx
-
+
# We use a different prefix before nested lists than top-level lists.
# See extended comment in _ProcessListItems().
-
+
if ($this->list_level) {
$text = preg_replace_callback('{
^
@@ -1008,17 +1011,17 @@ class Markdown_Parser {
function _doLists_callback($matches) {
# Re-usable patterns to match list item bullets and number markers:
$marker_ul_re = '[*+-]';
- $marker_ol_re = '\d+[.]';
+ $marker_ol_re = '\d+[\.]';
$marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
-
+
$list = $matches[1];
- $list_type = preg_match("/$marker_ul_re/", $matches[3]) ? "ul" : "ol";
-
+ $list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
+
$marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
-
+
$list .= "\n";
$result = $this->processListItems($list, $marker_any_re);
-
+
$result = $this->hashBlock("<$list_type>\n" . $result . "</$list_type>");
return "\n". $result ."\n\n";
}
@@ -1050,7 +1053,7 @@ class Markdown_Parser {
# without resorting to mind-reading. Perhaps the solution is to
# change the syntax rules such that sub-lists must start with a
# starting cardinal number; e.g. "1." or "a.".
-
+
$this->list_level++;
# trim trailing blank lines:
@@ -1078,7 +1081,7 @@ class Markdown_Parser {
$marker_space = $matches[3];
$tailing_blank_line =& $matches[5];
- if ($leading_line || $tailing_blank_line ||
+ if ($leading_line || $tailing_blank_line ||
preg_match('/\n{2,}/', $item))
{
# Replace marker with the appropriate whitespace indentation
@@ -1138,25 +1141,25 @@ class Markdown_Parser {
var $em_relist = array(
- '' => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S)(?![.,:;]\s)',
- '*' => '(?<=\S)(?<!\*)\*(?!\*)',
- '_' => '(?<=\S)(?<!_)_(?!_)',
+ '' => '(?:(?<!\*)\*(?!\*)|(?<!_)_(?!_))(?=\S|$)(?![\.,:;]\s)',
+ '*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
+ '_' => '(?<=\S|^)(?<!_)_(?!_)',
);
var $strong_relist = array(
- '' => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S)(?![.,:;]\s)',
- '**' => '(?<=\S)(?<!\*)\*\*(?!\*)',
- '__' => '(?<=\S)(?<!_)__(?!_)',
+ '' => '(?:(?<!\*)\*\*(?!\*)|(?<!_)__(?!_))(?=\S|$)(?![\.,:;]\s)',
+ '**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
+ '__' => '(?<=\S|^)(?<!_)__(?!_)',
);
var $em_strong_relist = array(
- '' => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S)(?![.,:;]\s)',
- '***' => '(?<=\S)(?<!\*)\*\*\*(?!\*)',
- '___' => '(?<=\S)(?<!_)___(?!_)',
+ '' => '(?:(?<!\*)\*\*\*(?!\*)|(?<!_)___(?!_))(?=\S|$)(?![\.,:;]\s)',
+ '***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
+ '___' => '(?<=\S|^)(?<!_)___(?!_)',
);
var $em_strong_prepared_relist;
-
+
function prepareItalicsAndBold() {
#
- # Prepare regular expressions for seraching emphasis tokens in any
+ # Prepare regular expressions for searching emphasis tokens in any
# context.
#
foreach ($this->em_relist as $em => $em_re) {
@@ -1168,37 +1171,37 @@ class Markdown_Parser {
}
$token_relist[] = $em_re;
$token_relist[] = $strong_re;
-
+
# Construct master expression from list.
$token_re = '{('. implode('|', $token_relist) .')}';
$this->em_strong_prepared_relist["$em$strong"] = $token_re;
}
}
}
-
+
function doItalicsAndBold($text) {
$token_stack = array('');
$text_stack = array('');
$em = '';
$strong = '';
$tree_char_em = false;
-
+
while (1) {
#
# Get prepared regular expression for seraching emphasis tokens
# in current context.
#
$token_re = $this->em_strong_prepared_relist["$em$strong"];
-
+
#
- # Each loop iteration seach for the next emphasis token.
+ # Each loop iteration search for the next emphasis token.
# Each token is then passed to handleSpanToken.
#
$parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
$text_stack[0] .= $parts[0];
$token =& $parts[1];
$text =& $parts[2];
-
+
if (empty($token)) {
# Reached end of text span: empty stack without emitting.
# any more emphasis.
@@ -1208,7 +1211,7 @@ class Markdown_Parser {
}
break;
}
-
+
$token_len = strlen($token);
if ($tree_char_em) {
# Reached closing marker while inside a three-char emphasis.
@@ -1247,7 +1250,7 @@ class Markdown_Parser {
$$tag = ''; # $$tag stands for $em or $strong
}
} else {
- # Reached opening three-char emphasis marker. Push on token
+ # Reached opening three-char emphasis marker. Push on token
# stack; will be handled by the special condition above.
$em = $token{0};
$strong = "$em$em";
@@ -1321,10 +1324,10 @@ class Markdown_Parser {
$bq = $this->runBlockGamut($bq); # recurse
$bq = preg_replace('/^/m', " ", $bq);
- # These leading spaces cause problem with <pre> content,
+ # These leading spaces cause problem with <pre> content,
# so we need to fix that:
- $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
- array(&$this, '_DoBlockQuotes_callback2'), $bq);
+ $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
+ array(&$this, '_doBlockQuotes_callback2'), $bq);
return "\n". $this->hashBlock("<blockquote>\n$bq\n</blockquote>")."\n\n";
}
@@ -1386,7 +1389,7 @@ class Markdown_Parser {
// # We can't call Markdown(), because that resets the hash;
// # that initialization code should be pulled into its own sub, though.
// $div_content = $this->hashHTMLBlocks($div_content);
-//
+//
// # Run document gamut methods on the content.
// foreach ($this->document_gamut as $method => $priority) {
// $div_content = $this->$method($div_content);
@@ -1414,11 +1417,11 @@ class Markdown_Parser {
$text = str_replace('"', '&quot;', $text);
return $text;
}
-
-
+
+
function encodeAmpsAndAngles($text) {
#
- # Smart processing for ampersands and angle brackets that need to
+ # Smart processing for ampersands and angle brackets that need to
# be encoded. Valid character entities are left alone unless the
# no-entities mode is set.
#
@@ -1427,7 +1430,7 @@ class Markdown_Parser {
} else {
# Ampersand-encoding based entirely on Nat Irons's Amputator
# MT plugin: <http://bumppo.net/projects/amputator/>
- $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
+ $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
'&amp;', $text);;
}
# Encode remaining <'s
@@ -1438,7 +1441,7 @@ class Markdown_Parser {
function doAutoLinks($text) {
- $text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i',
+ $text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i',
array(&$this, '_doAutoLinks_url_callback'), $text);
# Email addresses: <address@domain.foo>
@@ -1446,9 +1449,17 @@ class Markdown_Parser {
<
(?:mailto:)?
(
- [-.\w\x80-\xFF]+
+ (?:
+ [-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+
+ |
+ ".*?"
+ )
\@
- [-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
+ (?:
+ [-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+
+ |
+ \[[\d.a-fA-F:]+\] # IPv4 & IPv6
+ )
)
>
}xi',
@@ -1487,7 +1498,7 @@ class Markdown_Parser {
$addr = "mailto:" . $addr;
$chars = preg_split('/(?<!^)(?!$)/', $addr);
$seed = (int)abs(crc32($addr) / strlen($addr)); # Deterministic seed.
-
+
foreach ($chars as $key => $char) {
$ord = ord($char);
# Ignore non-ascii chars.
@@ -1500,7 +1511,7 @@ class Markdown_Parser {
else $chars[$key] = '&#'.$ord.';';
}
}
-
+
$addr = implode('', $chars);
$text = implode('', array_slice($chars, 7)); # text without `mailto:`
$addr = "<a href=\"$addr\">$text</a>";
@@ -1515,7 +1526,7 @@ class Markdown_Parser {
# escaped characters and handling code spans.
#
$output = '';
-
+
$span_re = '{
(
\\\\'.$this->escape_chars_re.'
@@ -1540,17 +1551,17 @@ class Markdown_Parser {
while (1) {
#
- # Each loop iteration seach for either the next tag, the next
- # openning code span marker, or the next escaped character.
+ # Each loop iteration seach for either the next tag, the next
+ # openning code span marker, or the next escaped character.
# Each token is then passed to handleSpanToken.
#
$parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
-
+
# Create token from text preceding tag.
if ($parts[0] != "") {
$output .= $parts[0];
}
-
+
# Check if we reach the end.
if (isset($parts[1])) {
$output .= $this->handleSpanToken($parts[1], $parts[2]);
@@ -1560,14 +1571,14 @@ class Markdown_Parser {
break;
}
}
-
+
return $output;
}
-
-
+
+
function handleSpanToken($token, &$str) {
#
- # Handle $token provided by parseSpan by determining its nature and
+ # Handle $token provided by parseSpan by determining its nature and
# returning the corresponding value that should replace it.
#
switch ($token{0}) {
@@ -1575,7 +1586,7 @@ class Markdown_Parser {
return $this->hashPart("&#". ord($token{1}). ";");
case "`":
# Search for end marker in remaining text.
- if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
+ if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
$str, $matches))
{
$str = $matches[2];
@@ -1597,18 +1608,18 @@ class Markdown_Parser {
}
- # String length function for detab. `_initDetab` will create a function to
+ # String length function for detab. `_initDetab` will create a function to
# hanlde UTF-8 if the default function does not exist.
var $utf8_strlen = 'mb_strlen';
-
+
function detab($text) {
#
# Replace tabs with the appropriate amount of space.
#
# For each line we separate the line in blocks delemited by
- # tab characters. Then we reconstruct every line by adding the
+ # tab characters. Then we reconstruct every line by adding the
# appropriate number of space between each blocks.
-
+
$text = preg_replace_callback('/^.*\t.*$/m',
array(&$this, '_detab_callback'), $text);
@@ -1617,7 +1628,7 @@ class Markdown_Parser {
function _detab_callback($matches) {
$line = $matches[0];
$strlen = $this->utf8_strlen; # strlen function for UTF-8.
-
+
# Split in blocks.
$blocks = explode("\t", $line);
# Add each blocks to the line.
@@ -1625,7 +1636,7 @@ class Markdown_Parser {
unset($blocks[0]); # Do not add first block twice.
foreach ($blocks as $block) {
# Calculate amount of space, insert spaces, insert block.
- $amount = $this->tab_width -
+ $amount = $this->tab_width -
$strlen($line, 'UTF-8') % $this->tab_width;
$line .= str_repeat(" ", $amount) . $block;
}
@@ -1634,13 +1645,13 @@ class Markdown_Parser {
function _initDetab() {
#
# Check for the availability of the function in the `utf8_strlen` property
- # (initially `mb_strlen`). If the function is not available, create a
+ # (initially `mb_strlen`). If the function is not available, create a
# function that will loosely count the number of UTF-8 characters with a
# regular expression.
#
if (function_exists($this->utf8_strlen)) return;
$this->utf8_strlen = create_function('$text', 'return preg_match_all(
- "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
+ "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
$text, $m);');
}
@@ -1649,7 +1660,7 @@ class Markdown_Parser {
#
# Swap back in all the tags hashed by _HashHTMLBlocks.
#
- return preg_replace_callback('/(.)\x1A[0-9]+\1/',
+ return preg_replace_callback('/(.)\x1A[0-9]+\1/',
array(&$this, '_unhash_callback'), $text);
}
function _unhash_callback($matches) {
@@ -1667,24 +1678,15 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Prefix for footnote ids.
var $fn_id_prefix = "";
-
+
# Optional title attribute for footnote links and backlinks.
var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
-
+
# Optional class attribute for footnote links and backlinks.
var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
-
- var $el_enable = MARKDOWN_EL_ENABLE;
- var $el_local_domain = MARKDOWN_EL_LOCAL_DOMAIN;
- var $el_new_window = MARKDOWN_EL_NEW_WINDOW;
- var $el_css_class = MARKDOWN_EL_CSS_CLASS;
-
- var $ha_enable = MARKDOWN_HA_ENABLE;
- var $ha_class = MARKDOWN_HA_CLASS;
- var $ha_text = MARKDOWN_HA_TEXT;
-
+
# Predefined abbreviations.
var $predef_abbr = array();
@@ -1693,15 +1695,11 @@ class MarkdownExtra_Parser extends Markdown_Parser {
#
# Constructor function. Initialize the parser object.
#
- # Add extra escapable characters before parent constructor
+ # Add extra escapable characters before parent constructor
# initialize the table.
$this->escape_chars .= ':|';
-
- if ($this->el_local_domain === null) {
- $this->el_local_domain = $_SERVER['SERVER_NAME'];
- }
-
- # Insert extra document, block, and span transformations.
+
+ # Insert extra document, block, and span transformations.
# Parent constructor will do the sorting.
$this->document_gamut += array(
"doFencedCodeBlocks" => 5,
@@ -1718,33 +1716,33 @@ class MarkdownExtra_Parser extends Markdown_Parser {
"doFootnotes" => 5,
"doAbbreviations" => 70,
);
-
+
parent::Markdown_Parser();
}
-
-
+
+
# Extra variables used during extra transformations.
var $footnotes = array();
var $footnotes_ordered = array();
var $abbr_desciptions = array();
var $abbr_word_re = '';
-
+
# Give the current footnote number.
var $footnote_counter = 1;
-
-
+
+
function setup() {
#
# Setting up Extra-specific variables.
#
parent::setup();
-
+
$this->footnotes = array();
$this->footnotes_ordered = array();
$this->abbr_desciptions = array();
$this->abbr_word_re = '';
$this->footnote_counter = 1;
-
+
foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
if ($this->abbr_word_re)
$this->abbr_word_re .= '|';
@@ -1752,7 +1750,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
}
}
-
+
function teardown() {
#
# Clearing Extra-specific variables.
@@ -1761,29 +1759,29 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$this->footnotes_ordered = array();
$this->abbr_desciptions = array();
$this->abbr_word_re = '';
-
+
parent::teardown();
}
-
-
+
+
### HTML Block Parser ###
-
+
# Tags that are always treated as block tags:
var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
-
+
# Tags treated as block tags only if the opening tag is alone on it's line:
var $context_block_tags_re = 'script|noscript|math|ins|del';
-
+
# Tags where markdown="1" default to span mode:
var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
-
- # Tags which must not have their contents modified, no matter where
+
+ # Tags which must not have their contents modified, no matter where
# they appear:
var $clean_tags_re = 'script|math';
-
+
# Tags that do not need to be closed.
var $auto_close_tags_re = 'hr|img';
-
+
function hashHTMLBlocks($text) {
#
@@ -1796,7 +1794,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# hard-coded.
#
# This works by calling _HashHTMLBlocks_InMarkdown, which then calls
- # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
+ # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
# attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
# _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
# These two functions are calling each other. It's recursive!
@@ -1805,17 +1803,17 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Call the HTML-in-Markdown hasher.
#
list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text);
-
+
return $text;
}
- function _hashHTMLBlocks_inMarkdown($text, $indent = 0,
+ function _hashHTMLBlocks_inMarkdown($text, $indent = 0,
$enclosing_tag_re = '', $span = false)
{
#
# Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
#
- # * $indent is the number of space to be ignored when checking for code
- # blocks. This is important because if we don't take the indent into
+ # * $indent is the number of space to be ignored when checking for code
+ # blocks. This is important because if we don't take the indent into
# account, something like this (which looks right) won't work as expected:
#
# <div>
@@ -1827,11 +1825,11 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# If you don't like this, just don't indent the tag on which
# you apply the markdown="1" attribute.
#
- # * If $enclosing_tag_re is not empty, stops at the first unmatched closing
+ # * If $enclosing_tag_re is not empty, stops at the first unmatched closing
# tag with that name. Nested tags supported.
#
- # * If $span is true, text inside must treated as span. So any double
- # newline will be replaced by a single newline so that it does not create
+ # * If $span is true, text inside must treated as span. So any double
+ # newline will be replaced by a single newline so that it does not create
# paragraphs.
#
# Returns an array of that form: ( processed text , remaining text )
@@ -1840,13 +1838,13 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Regex to check for the presense of newlines around a block tag.
$newline_before_re = '/(?:^\n?|\n\n)*$/';
- $newline_after_re =
+ $newline_after_re =
'{
^ # Start of text following the tag.
(?>[ ]*<!--.*?-->)? # Optional comment.
[ ]*\n # Must be followed by newline.
}xs';
-
+
# Regex to match any tag.
$block_tag_re =
'{
@@ -1879,7 +1877,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
'. ( !$span ? ' # If not in span.
|
# Indented code block
- (?> ^[ ]*\n? | \n[ ]*\n )
+ (?: ^[ ]*\n | ^ | \n[ ]*\n )
[ ]{'.($indent+4).'}[^\n]* \n
(?>
(?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
@@ -1887,12 +1885,12 @@ class MarkdownExtra_Parser extends Markdown_Parser {
|
# Fenced code block marker
(?> ^ | \n )
- [ ]{'.($indent).'}~~~+[ ]*\n
+ [ ]{0,'.($indent).'}~~~+[ ]*\n
' : '' ). ' # End (if not is span).
)
}xs';
-
+
$depth = 0; # Current depth inside the tag tree.
$parsed = ""; # Parsed text that will be returned.
@@ -1904,32 +1902,32 @@ class MarkdownExtra_Parser extends Markdown_Parser {
#
# Split the text using the first $tag_match pattern found.
# Text before pattern will be first in the array, text after
- # pattern will be at the end, and between will be any catches made
+ # pattern will be at the end, and between will be any catches made
# by the pattern.
#
- $parts = preg_split($block_tag_re, $text, 2,
+ $parts = preg_split($block_tag_re, $text, 2,
PREG_SPLIT_DELIM_CAPTURE);
-
- # If in Markdown span mode, add a empty-string span-level hash
+
+ # If in Markdown span mode, add a empty-string span-level hash
# after each newline to prevent triggering any block element.
if ($span) {
$void = $this->hashPart("", ':');
$newline = "$void\n";
$parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
}
-
+
$parsed .= $parts[0]; # Text before current tag.
-
+
# If end of $text has been reached. Stop loop.
if (count($parts) < 3) {
$text = "";
break;
}
-
+
$tag = $parts[1]; # Tag to handle.
$text = $parts[2]; # Remaining text after current tag.
$tag_re = preg_quote($tag); # For use in a regular expression.
-
+
#
# Check for: Code span marker
#
@@ -1949,33 +1947,34 @@ class MarkdownExtra_Parser extends Markdown_Parser {
}
}
#
- # Check for: Indented code block or fenced code block marker.
+ # Check for: Fenced code block marker.
#
- else if ($tag{0} == "\n" || $tag{0} == "~") {
- if ($tag{1} == "\n" || $tag{1} == " ") {
- # Indented code block: pass it unchanged, will be handled
- # later.
- $parsed .= $tag;
+ else if (preg_match('{^\n?[ ]{0,'.($indent+3).'}~}', $tag)) {
+ # Fenced code block marker: find matching end marker.
+ $tag_re = preg_quote(trim($tag));
+ if (preg_match('{^(?>.*\n)+?[ ]{0,'.($indent).'}'.$tag_re.'[ ]*\n}', $text,
+ $matches))
+ {
+ # End marker found: pass text unchanged until marker.
+ $parsed .= $tag . $matches[0];
+ $text = substr($text, strlen($matches[0]));
}
else {
- # Fenced code block marker: find matching end marker.
- $tag_re = preg_quote(trim($tag));
- if (preg_match('{^(?>.*\n)+?'.$tag_re.' *\n}', $text,
- $matches))
- {
- # End marker found: pass text unchanged until marker.
- $parsed .= $tag . $matches[0];
- $text = substr($text, strlen($matches[0]));
- }
- else {
- # No end marker: just skip it.
- $parsed .= $tag;
- }
+ # No end marker: just skip it.
+ $parsed .= $tag;
}
}
#
+ # Check for: Indented code block.
+ #
+ else if ($tag{0} == "\n" || $tag{0} == " ") {
+ # Indented code block: pass it unchanged, will be handled
+ # later.
+ $parsed .= $tag;
+ }
+ #
# Check for: Opening Block level tag or
- # Opening Context Block tag (like ins and del)
+ # Opening Context Block tag (like ins and del)
# used as a block tag (tag is alone on it's line).
#
else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
@@ -1985,9 +1984,9 @@ class MarkdownExtra_Parser extends Markdown_Parser {
)
{
# Need to parse tag and following text using the HTML parser.
- list($block_text, $text) =
+ list($block_text, $text) =
$this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
-
+
# Make sure it stays outside of any paragraph by adding newlines.
$parsed .= "\n\n$block_text\n\n";
}
@@ -2000,9 +1999,9 @@ class MarkdownExtra_Parser extends Markdown_Parser {
{
# Need to parse tag and following text using the HTML parser.
# (don't check for markdown attribute)
- list($block_text, $text) =
+ list($block_text, $text) =
$this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
-
+
$parsed .= $block_text;
}
#
@@ -2026,14 +2025,14 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$text = $tag . $text;
break;
}
-
+
$parsed .= $tag;
}
else {
$parsed .= $tag;
}
} while ($depth >= 0);
-
+
return array($parsed, $text);
}
function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) {
@@ -2048,7 +2047,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Returns an array of that form: ( processed text , remaining text )
#
if ($text === '') return array('', '');
-
+
# Regex to match `markdown` attribute inside of a tag.
$markdown_attr_re = '
{
@@ -2056,15 +2055,15 @@ class MarkdownExtra_Parser extends Markdown_Parser {
markdown
\s*=\s*
(?>
- (["\']) # $1: quote delimiter
+ (["\']) # $1: quote delimiter
(.*?) # $2: attribute value
- \1 # matching delimiter
+ \1 # matching delimiter
|
([^\s>]*) # $3: unquoted attribute value
)
() # $4: make $3 always defined (avoid warnings)
}xs';
-
+
# Regex to match any tag.
$tag_re = '{
( # $2: Capture hole tag.
@@ -2087,9 +2086,9 @@ class MarkdownExtra_Parser extends Markdown_Parser {
<!\[CDATA\[.*?\]\]> # CData Block
)
}xs';
-
+
$original_text = $text; # Save original text in case of faliure.
-
+
$depth = 0; # Current depth inside the tag tree.
$block_text = ""; # Temporary text holder for current text.
$parsed = ""; # Parsed text that will be returned.
@@ -2108,25 +2107,25 @@ class MarkdownExtra_Parser extends Markdown_Parser {
#
# Split the text using the first $tag_match pattern found.
# Text before pattern will be first in the array, text after
- # pattern will be at the end, and between will be any catches made
+ # pattern will be at the end, and between will be any catches made
# by the pattern.
#
$parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
-
+
if (count($parts) < 3) {
#
# End of $text reached with unbalenced tag(s).
# In that case, we return original text unchanged and pass the
- # first character as filtered to prevent an infinite loop in the
+ # first character as filtered to prevent an infinite loop in the
# parent function.
#
return array($original_text{0}, substr($original_text, 1));
}
-
+
$block_text .= $parts[0]; # Text before current tag.
$tag = $parts[1]; # Tag to handle.
$text = $parts[2]; # Remaining text after current tag.
-
+
#
# Check for: Auto-close tag (like <hr/>)
# Comments and Processing Instructions.
@@ -2146,22 +2145,22 @@ class MarkdownExtra_Parser extends Markdown_Parser {
if ($tag{1} == '/') $depth--;
else if ($tag{strlen($tag)-2} != '/') $depth++;
}
-
+
#
# Check for `markdown="1"` attribute and handle it.
#
- if ($md_attr &&
+ if ($md_attr &&
preg_match($markdown_attr_re, $tag, $attr_m) &&
preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
{
# Remove `markdown` attribute from opening tag.
$tag = preg_replace($markdown_attr_re, '', $tag);
-
+
# Check if text inside this tag must be parsed in span mode.
$this->mode = $attr_m[2] . $attr_m[3];
$span_mode = $this->mode == 'span' || $this->mode != 'block' &&
preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
-
+
# Calculate indent before tag.
if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
$strlen = $this->utf8_strlen;
@@ -2169,44 +2168,44 @@ class MarkdownExtra_Parser extends Markdown_Parser {
} else {
$indent = 0;
}
-
+
# End preceding block with this tag.
$block_text .= $tag;
$parsed .= $this->$hash_method($block_text);
-
+
# Get enclosing tag name for the ParseMarkdown function.
# (This pattern makes $tag_name_re safe without quoting.)
preg_match('/^<([\w:$]*)\b/', $tag, $matches);
$tag_name_re = $matches[1];
-
+
# Parse the content using the HTML-in-Markdown parser.
list ($block_text, $text)
- = $this->_hashHTMLBlocks_inMarkdown($text, $indent,
+ = $this->_hashHTMLBlocks_inMarkdown($text, $indent,
$tag_name_re, $span_mode);
-
+
# Outdent markdown text.
if ($indent > 0) {
- $block_text = preg_replace("/^[ ]{1,$indent}/m", "",
+ $block_text = preg_replace("/^[ ]{1,$indent}/m", "",
$block_text);
}
-
+
# Append tag content to parsed text.
if (!$span_mode) $parsed .= "\n\n$block_text\n\n";
else $parsed .= "$block_text";
-
+
# Start over a new block.
$block_text = "";
}
else $block_text .= $tag;
}
-
+
} while ($depth > 0);
-
+
#
# Hash last block text that wasn't processed inside the loop.
#
$parsed .= $this->$hash_method($block_text);
-
+
return array($parsed, $text);
}
@@ -2214,87 +2213,12 @@ class MarkdownExtra_Parser extends Markdown_Parser {
function hashClean($text) {
#
# Called whenever a tag must be hashed when a function insert a "clean" tag
- # in $text, it pass through this function and is automaticaly escaped,
+ # in $text, it pass through this function and is automaticaly escaped,
# blocking invalid nested overlap.
#
return $this->hashPart($text, 'C');
}
- function _doAnchors_inline_callback($matches) {
- // $whole_match = $matches[1];
- $link_text = $this->runSpanGamut($matches[2]);
- $url = $matches[3] == '' ? $matches[4] : $matches[3];
- $title =& $matches[7];
-
- $url = $this->encodeAttribute($url);
-
- $result = "<a href=\"$url\"";
- if (isset($title)) {
- $title = $this->encodeAttribute($title);
- $result .= " title=\"$title\"";
- }
-
- if ($this->el_enable && preg_match('/^https?\:\/\//', $url) && !preg_match('/^https?\:\/\/'.$this->el_local_domain.'/', $url)) {
- if ($this->el_new_window) {
- $result .= ' target="_blank"';
- }
-
- if ($this->el_css_class) {
- $result .= ' class="'.$this->el_css_class.'"';
- }
- }
-
- $link_text = $this->runSpanGamut($link_text);
- $result .= ">$link_text</a>";
-
- return $this->hashPart($result);
- }
-
- function _doAnchors_reference_callback($matches) {
- $whole_match = $matches[1];
- $link_text = $matches[2];
- $link_id =& $matches[3];
- $result = '';
-
- if ($link_id == "") {
- # for shortcut links like [this][] or [this].
- $link_id = $link_text;
- }
-
- # lower-case and turn embedded newlines into spaces
- $link_id = strtolower($link_id);
- $link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
-
- if (isset($this->urls[$link_id])) {
- $url = $this->urls[$link_id];
- $url = $this->encodeAttribute($url);
-
- $result = "<a href=\"$url\"";
- if ( isset( $this->titles[$link_id] ) ) {
- $title = $this->titles[$link_id];
- $title = $this->encodeAttribute($title);
- $result .= " title=\"$title\"";
- }
-
- if ($this->el_enable && preg_match('/^https?\:\/\//', $url) && !preg_match('/^https?\:\/\/'.$this->el_local_domain.'/', $url)) {
- if ($this->el_new_window) {
- $result .= ' target="_blank"';
- }
-
- if ($this->el_css_class) {
- $result .= ' class="'.$this->el_css_class.'"';
- }
- }
-
- $link_text = $this->runSpanGamut($link_text);
- $result .= ">$link_text</a>";
- $result = $this->hashPart($result);
- }
- else {
- $result = $whole_match;
- }
- return $result;
- }
function doHeaders($text) {
#
@@ -2303,7 +2227,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Setext-style headers:
# Header 1 {#header1}
# ========
- #
+ #
# Header 2 {#header2}
# --------
#
@@ -2345,36 +2269,15 @@ class MarkdownExtra_Parser extends Markdown_Parser {
return $matches[0];
$level = $matches[3]{0} == '=' ? 1 : 2;
$attr = $this->_doHeaders_attr($id =& $matches[2]);
- $body = $this->runSpanGamut($matches[1]);
- $body = $this->_doHeaders_selflink($id, $body);
-
- $block = "<h$level$attr>$body</h$level>";
+ $block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
return "\n" . $this->hashBlock($block) . "\n\n";
}
function _doHeaders_callback_atx($matches) {
$level = strlen($matches[1]);
$attr = $this->_doHeaders_attr($id =& $matches[3]);
- $body = $this->runSpanGamut($matches[2]);
- $body = $this->_doHeaders_selflink($id, $body);
-
- $block = "<h$level$attr>$body</h$level>";
+ $block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>";
return "\n" . $this->hashBlock($block) . "\n\n";
}
- function _doHeaders_selflink($id, $body) {
- if (!empty($id)) {
- $link = '<a href="#'.$id.'"';
-
- if ($this->ha_class) {
- $link .= ' class="'.$this->ha_class.'"';
- }
-
- $link .= '>'.$this->ha_text.'</a>';
-
- $body .= $link;
- }
-
- return $body;
- }
function doTables($text) {
@@ -2396,10 +2299,10 @@ class MarkdownExtra_Parser extends Markdown_Parser {
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
[|] # Optional leading pipe (present)
(.+) \n # $1: Header row (at least one pipe)
-
+
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
[|] ([ ]*[-:]+[-| :]*) \n # $2: Header underline
-
+
( # $3: Cells
(?>
[ ]* # Allowed whitespace.
@@ -2409,7 +2312,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
(?=\n|\Z) # Stop at final double newline.
}xm',
array(&$this, '_doTable_leadingPipe_callback'), $text);
-
+
#
# Find tables without leading pipe.
#
@@ -2423,10 +2326,10 @@ class MarkdownExtra_Parser extends Markdown_Parser {
^ # Start of a line
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
(\S.*[|].*) \n # $1: Header row (at least one pipe)
-
+
[ ]{0,'.$less_than_tab.'} # Allowed whitespace.
([-:]+[ ]*[|][-| :]*) \n # $2: Header underline
-
+
( # $3: Cells
(?>
.* [|] .* \n # Row content
@@ -2442,10 +2345,10 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$head = $matches[1];
$underline = $matches[2];
$content = $matches[3];
-
+
# Remove leading pipe for each row.
$content = preg_replace('/^ *[|]/m', '', $content);
-
+
return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
}
function _doTable_callback($matches) {
@@ -2457,7 +2360,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$head = preg_replace('/[|] *$/m', '', $head);
$underline = preg_replace('/[|] *$/m', '', $underline);
$content = preg_replace('/[|] *$/m', '', $content);
-
+
# Reading alignement from header underline.
$separators = preg_split('/ *[|] */', $underline);
foreach ($separators as $n => $s) {
@@ -2466,13 +2369,13 @@ class MarkdownExtra_Parser extends Markdown_Parser {
else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"';
else $attr[$n] = '';
}
-
- # Parsing span elements, including code spans, character escapes,
+
+ # Parsing span elements, including code spans, character escapes,
# and inline HTML tags, so that pipes inside those gets ignored.
$head = $this->parseSpan($head);
$headers = preg_split('/ *[|] */', $head);
$col_count = count($headers);
-
+
# Write column headers.
$text = "<table>\n";
$text .= "<thead>\n";
@@ -2481,20 +2384,20 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$text .= " <th$attr[$n]>".$this->runSpanGamut(trim($header))."</th>\n";
$text .= "</tr>\n";
$text .= "</thead>\n";
-
+
# Split content by row.
$rows = explode("\n", trim($content, "\n"));
-
+
$text .= "<tbody>\n";
foreach ($rows as $row) {
- # Parsing span elements, including code spans, character escapes,
+ # Parsing span elements, including code spans, character escapes,
# and inline HTML tags, so that pipes inside those gets ignored.
$row = $this->parseSpan($row);
-
+
# Split row by cell.
$row_cells = preg_split('/ *[|] */', $row, $col_count);
$row_cells = array_pad($row_cells, $col_count, '');
-
+
$text .= "<tr>\n";
foreach ($row_cells as $n => $cell)
$text .= " <td$attr[$n]>".$this->runSpanGamut(trim($cell))."</td>\n";
@@ -2502,11 +2405,11 @@ class MarkdownExtra_Parser extends Markdown_Parser {
}
$text .= "</tbody>\n";
$text .= "</table>";
-
+
return $this->hashBlock($text) . "\n";
}
-
+
function doDefLists($text) {
#
# Form HTML definition lists.
@@ -2552,7 +2455,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
function _doDefLists_callback($matches) {
# Re-usable patterns to match list item bullets and number markers:
$list = $matches[1];
-
+
# Turn double returns into triple returns, so that we can make a
# paragraph for the last item in a list, if necessary:
$result = trim($this->processDefListItems($list));
@@ -2567,7 +2470,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# into individual term and definition list items.
#
$less_than_tab = $this->tab_width - 1;
-
+
# trim trailing blank lines:
$list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
@@ -2576,11 +2479,11 @@ class MarkdownExtra_Parser extends Markdown_Parser {
(?>\A\n?|\n\n+) # leading line
( # definition terms = $1
[ ]{0,'.$less_than_tab.'} # leading whitespace
- (?![:][ ]|[ ]) # negative lookahead for a definition
+ (?![:][ ]|[ ]) # negative lookahead for a definition
# mark (colon) or more whitespace.
- (?> \S.* \n)+? # actual term (not whitespace).
- )
- (?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed
+ (?> \S.* \n)+? # actual term (not whitespace).
+ )
+ (?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed
# with a definition mark.
}xm',
array(&$this, '_processDefListItems_callback_dt'), $list_str);
@@ -2596,33 +2499,20 @@ class MarkdownExtra_Parser extends Markdown_Parser {
(?= \n+ # stop at next definition mark,
(?: # next term or end of text
[ ]{0,'.$less_than_tab.'} [:][ ] |
- <dt | \z
- )
- )
+ <dt> | \z
+ )
+ )
}xm',
array(&$this, '_processDefListItems_callback_dd'), $list_str);
return $list_str;
}
function _processDefListItems_callback_dt($matches) {
- $anchor_regexp = '/\{\#([-_:a-zA-Z0-9]+)\}/';
$terms = explode("\n", trim($matches[1]));
$text = '';
- $id = array();
-
foreach ($terms as $term) {
- $id = '';
- if (preg_match($anchor_regexp, $term, $id) > 0) {
- $term = preg_replace($anchor_regexp, '', $term);
- $id = ' id="'.trim($id[1]).'"';
- }
-
- if (count($id) === 0) {
- $id = '';
- }
-
$term = $this->runSpanGamut(trim($term));
- $text .= "\n<dt$id>" . $term . "</dt>";
+ $text .= "\n<dt>" . $term . "</dt>";
}
return $text . "\n";
}
@@ -2655,7 +2545,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# ~~~
#
$less_than_tab = $this->tab_width;
-
+
$text = preg_replace_callback('{
(?:\n|\A)
# 1: Opening marker
@@ -2663,7 +2553,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
~{3,} # Marker: three tilde or more.
)
[ ]* \n # Whitespace and newline following marker.
-
+
# 2: Content
(
(?>
@@ -2671,7 +2561,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
.*\n+
)+
)
-
+
# Closing marker.
\1 [ ]* \n
}xm',
@@ -2688,7 +2578,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
return "\n\n".$this->hashBlock($codeblock)."\n\n";
}
function _doFencedCodeBlocks_newlines($matches) {
- return str_repeat("<br$this->empty_element_suffix",
+ return str_repeat("<br$this->empty_element_suffix",
strlen($matches[0]));
}
@@ -2698,19 +2588,19 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# work in the middle of a word.
#
var $em_relist = array(
- '' => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S)(?![.,:;]\s)',
- '*' => '(?<=\S)(?<!\*)\*(?!\*)',
- '_' => '(?<=\S)(?<!_)_(?![a-zA-Z0-9_])',
+ '' => '(?:(?<!\*)\*(?!\*)|(?<![a-zA-Z0-9_])_(?!_))(?=\S|$)(?![\.,:;]\s)',
+ '*' => '(?<=\S|^)(?<!\*)\*(?!\*)',
+ '_' => '(?<=\S|^)(?<!_)_(?![a-zA-Z0-9_])',
);
var $strong_relist = array(
- '' => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S)(?![.,:;]\s)',
- '**' => '(?<=\S)(?<!\*)\*\*(?!\*)',
- '__' => '(?<=\S)(?<!_)__(?![a-zA-Z0-9_])',
+ '' => '(?:(?<!\*)\*\*(?!\*)|(?<![a-zA-Z0-9_])__(?!_))(?=\S|$)(?![\.,:;]\s)',
+ '**' => '(?<=\S|^)(?<!\*)\*\*(?!\*)',
+ '__' => '(?<=\S|^)(?<!_)__(?![a-zA-Z0-9_])',
);
var $em_strong_relist = array(
- '' => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S)(?![.,:;]\s)',
- '***' => '(?<=\S)(?<!\*)\*\*\*(?!\*)',
- '___' => '(?<=\S)(?<!_)___(?![a-zA-Z0-9_])',
+ '' => '(?:(?<!\*)\*\*\*(?!\*)|(?<![a-zA-Z0-9_])___(?!_))(?=\S|$)(?![\.,:;]\s)',
+ '***' => '(?<=\S|^)(?<!\*)\*\*\*(?!\*)',
+ '___' => '(?<=\S|^)(?<!_)___(?![a-zA-Z0-9_])',
);
@@ -2721,7 +2611,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
#
# Strip leading and trailing lines:
$text = preg_replace('/\A\n+|\n+\z/', '', $text);
-
+
$grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
#
@@ -2729,29 +2619,29 @@ class MarkdownExtra_Parser extends Markdown_Parser {
#
foreach ($grafs as $key => $value) {
$value = trim($this->runSpanGamut($value));
-
+
# Check if this should be enclosed in a paragraph.
# Clean tag hashes & block tag hashes are left alone.
$is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
-
+
if ($is_p) {
$value = "<p>$value</p>";
}
$grafs[$key] = $value;
}
-
- # Join grafs in one text, then unhash HTML tags.
+
+ # Join grafs in one text, then unhash HTML tags.
$text = implode("\n\n", $grafs);
-
+
# Finish by removing any tag hashes still present in $text.
$text = $this->unhash($text);
-
+
return $text;
}
-
-
+
+
### Footnotes
-
+
function stripFootnotes($text) {
#
# Strips link definitions from text, stores the URLs and titles in
@@ -2765,15 +2655,15 @@ class MarkdownExtra_Parser extends Markdown_Parser {
[ ]*
\n? # maybe *one* newline
( # text = $2 (no blank lines allowed)
- (?:
+ (?:
.+ # actual text
|
- \n # newlines but
+ \n # newlines but
(?!\[\^.+?\]:\s)# negative lookahead for footnote marker.
- (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed
+ (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed
# by non-indented content
)*
- )
+ )
}xm',
array(&$this, '_stripFootnotes_callback'),
$text);
@@ -2788,7 +2678,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
function doFootnotes($text) {
#
- # Replace footnote references in $text [^id] with a special text-token
+ # Replace footnote references in $text [^id] with a special text-token
# which will be replaced by the actual footnote marker in appendFootnotes.
#
if (!$this->in_anchor) {
@@ -2797,20 +2687,20 @@ class MarkdownExtra_Parser extends Markdown_Parser {
return $text;
}
-
+
function appendFootnotes($text) {
#
# Append footnote list to text.
#
- $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
+ $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
array(&$this, '_appendFootnotes_callback'), $text);
-
+
if (!empty($this->footnotes_ordered)) {
$text .= "\n\n";
$text .= "<div class=\"footnotes\">\n";
- $text .= "<hr". MARKDOWN_EMPTY_ELEMENT_SUFFIX ."\n";
+ $text .= "<hr". $this->empty_element_suffix ."\n";
$text .= "<ol>\n\n";
-
+
$attr = " rev=\"footnote\"";
if ($this->fn_backlink_class != "") {
$class = $this->fn_backlink_class;
@@ -2823,20 +2713,20 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$attr .= " title=\"$title\"";
}
$num = 0;
-
+
while (!empty($this->footnotes_ordered)) {
$footnote = reset($this->footnotes_ordered);
$note_id = key($this->footnotes_ordered);
unset($this->footnotes_ordered[$note_id]);
-
+
$footnote .= "\n"; # Need to append newline before parsing.
- $footnote = $this->runBlockGamut("$footnote\n");
- $footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
+ $footnote = $this->runBlockGamut("$footnote\n");
+ $footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
array(&$this, '_appendFootnotes_callback'), $footnote);
-
+
$attr = str_replace("%%", ++$num, $attr);
$note_id = $this->encodeAttribute($note_id);
-
+
# Add backlink to last paragraph; create new paragraph if needed.
$backlink = "<a href=\"#fnref:$note_id\"$attr>&#8617;</a>";
if (preg_match('{</p>$}', $footnote)) {
@@ -2844,12 +2734,12 @@ class MarkdownExtra_Parser extends Markdown_Parser {
} else {
$footnote .= "\n\n<p>$backlink</p>";
}
-
+
$text .= "<li id=\"fn:$note_id\">\n";
$text .= $footnote . "\n";
$text .= "</li>\n\n";
}
-
+
$text .= "</ol>\n";
$text .= "</div>";
}
@@ -2857,14 +2747,14 @@ class MarkdownExtra_Parser extends Markdown_Parser {
}
function _appendFootnotes_callback($matches) {
$node_id = $this->fn_id_prefix . $matches[1];
-
+
# Create footnote marker only if it has a corresponding footnote *and*
# the footnote hasn't been used by another marker.
if (isset($this->footnotes[$node_id])) {
# Transfert footnote content to the ordered list.
$this->footnotes_ordered[$node_id] = $this->footnotes[$node_id];
unset($this->footnotes[$node_id]);
-
+
$num = $this->footnote_counter++;
$attr = " rel=\"footnote\"";
if ($this->fn_link_class != "") {
@@ -2877,22 +2767,22 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$title = $this->encodeAttribute($title);
$attr .= " title=\"$title\"";
}
-
+
$attr = str_replace("%%", $num, $attr);
$node_id = $this->encodeAttribute($node_id);
-
+
return
"<sup id=\"fnref:$node_id\">".
"<a href=\"#fn:$node_id\"$attr>$num</a>".
"</sup>";
}
-
+
return "[^".$matches[1]."]";
}
-
-
+
+
### Abbreviations ###
-
+
function stripAbbreviations($text) {
#
# Strips abbreviations from text, stores titles in hash references.
@@ -2902,7 +2792,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Link defs are in the form: [id]*: url "optional title"
$text = preg_replace_callback('{
^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?: # abbr_id = $1
- (.*) # text = $2 (no blank lines allowed)
+ (.*) # text = $2 (no blank lines allowed)
}xm',
array(&$this, '_stripAbbreviations_callback'),
$text);
@@ -2917,20 +2807,20 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
return ''; # String that will replace the block
}
-
-
+
+
function doAbbreviations($text) {
#
# Find defined abbreviations in text and wrap them in <abbr> elements.
#
if ($this->abbr_word_re) {
- // cannot use the /x modifier because abbr_word_re may
+ // cannot use the /x modifier because abbr_word_re may
// contain significant spaces:
$text = preg_replace_callback('{'.
'(?<![\w\x1A])'.
'(?:'.$this->abbr_word_re.')'.
'(?![\w\x1A])'.
- '}',
+ '}',
array(&$this, '_doAbbreviations_callback'), $text);
}
return $text;
@@ -2961,9 +2851,9 @@ PHP Markdown Extra
Description
-----------
-This is a PHP port of the original Markdown formatter written in Perl
-by John Gruber. This special "Extra" version of PHP Markdown features
-further enhancements to the syntax for making additional constructs
+This is a PHP port of the original Markdown formatter written in Perl
+by John Gruber. This special "Extra" version of PHP Markdown features
+further enhancements to the syntax for making additional constructs
such as tables and definition list.
Markdown is a text-to-HTML filter; it translates an easy-to-read /
@@ -2993,7 +2883,7 @@ expected; (3) the output Markdown actually produced.
Version History
----------------
+---------------
See the readme file for detailed release notes for this version.
@@ -3001,14 +2891,14 @@ See the readme file for detailed release notes for this version.
Copyright and License
---------------------
-PHP Markdown & Extra
-Copyright (c) 2004-2008 Michel Fortin
-<http://www.michelf.com/>
+PHP Markdown & Extra
+Copyright (c) 2004-2009 Michel Fortin
+<http://michelf.com/>
All rights reserved.
-Based on Markdown
-Copyright (c) 2003-2006 John Gruber
-<http://daringfireball.net/>
+Based on Markdown
+Copyright (c) 2003-2006 John Gruber
+<http://daringfireball.net/>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -3039,4 +2929,4 @@ negligence or otherwise) arising in any way out of the use of this
software, even if advised of the possibility of such damage.
*/
-?>
+?> \ No newline at end of file
diff --git a/mod/group.php b/mod/group.php
index ca163902c..c896362ca 100755
--- a/mod/group.php
+++ b/mod/group.php
@@ -68,7 +68,7 @@ function group_content(&$a) {
return;
}
- // Switch to text mod interface if we have more than 'n' contacts or group members
+ // Switch to text mode interface if we have more than 'n' contacts or group members
$switchtotext = get_pconfig(local_user(),'system','groupedit_image_limit');
if($switchtotext === false)
diff --git a/mod/notify.php b/mod/notify.php
index d1e5022bc..229020f4a 100644
--- a/mod/notify.php
+++ b/mod/notify.php
@@ -20,6 +20,16 @@ function notify_init(&$a) {
goaway($a->get_baseurl());
}
+
+ if($a->argc > 2 && $a->argv[1] === 'mark' && $a->argv[2] === 'all' ) {
+ $r = q("update notify set seen = 1 where uid = %d",
+ intval(local_user())
+ );
+ $j = json_encode(array('result' => ($r) ? 'success' : 'fail'));
+ echo $j;
+ killme();
+ }
+
}
diff --git a/mod/wall_upload.php b/mod/wall_upload.php
index 278c21354..64f174a78 100755
--- a/mod/wall_upload.php
+++ b/mod/wall_upload.php
@@ -101,10 +101,24 @@ function wall_upload_post(&$a) {
$basename = basename($filename);
- if(local_user() && intval(get_pconfig(local_user(),'system','plaintext')))
- echo "\n\n" . '[url=' . $a->get_baseurl() . '/photos/' . $page_owner_nick . '/image/' . $hash . '][img]' . $a->get_baseurl() . "/photo/{$hash}-{$smallest}.jpg[/img][/url]\n\n";
- else
- echo '<br /><br /><a href="' . $a->get_baseurl() . '/photos/' . $page_owner_nick . '/image/' . $hash . '" ><img src="' . $a->get_baseurl() . "/photo/{$hash}-{$smallest}.jpg\" alt=\"$basename\" /></a><br /><br />";
+
+/* mod Waitman Gobble NO WARRANTY */
+
+//if we get the signal then return the image url info in BBCODE, otherwise this outputs the info and bails (for the ajax image uploader on wall post)
+ if ($_REQUEST['hush']!='yeah') {
+
+ /*existing code*/
+ if(local_user() && intval(get_pconfig(local_user(),'system','plaintext')))
+ echo "\n\n" . '[url=' . $a->get_baseurl() . '/photos/' . $page_owner_nick . '/image/' . $hash . '][img]' . $a->get_baseurl() . "/photo/{$hash}-{$smallest}.jpg[/img][/url]\n\n";
+ else
+ echo '<br /><br /><a href="' . $a->get_baseurl() . '/photos/' . $page_owner_nick . '/image/' . $hash . '" ><img src="' . $a->get_baseurl() . "/photo/{$hash}-{$smallest}.jpg\" alt=\"$basename\" /></a><br /><br />";
+ /*existing code*/
+
+ } else {
+ $m = '[url=' . $a->get_baseurl() . '/photos/' . $page_owner_nick . '/image/' . $hash . '][img]' . $a->get_baseurl() . "/photo/{$hash}-{$smallest}.jpg[/img][/url]";
+ return($m);
+ }
+/* mod Waitman Gobble NO WARRANTY */
killme();
// NOTREACHED
diff --git a/view/de/friend_complete_eml.tpl b/view/de/friend_complete_eml.tpl
index f6e0adf4c..908d0df40 100755
--- a/view/de/friend_complete_eml.tpl
+++ b/view/de/friend_complete_eml.tpl
@@ -1,5 +1,5 @@
-Lieber $username,
+Liebe/r $username,
großartige Neuigkeiten... '$fn' von '$dfrn_url' hat deine Kontaktaufnahme auf
'$sitename' bestätigt.
diff --git a/view/de/intro_complete_eml.tpl b/view/de/intro_complete_eml.tpl
index 46ffc8781..ff9b8a379 100755
--- a/view/de/intro_complete_eml.tpl
+++ b/view/de/intro_complete_eml.tpl
@@ -1,5 +1,5 @@
-Lieber $username,
+Liebe/r $username,
'$fn' von '$dfrn_url' hat deine Kontaktanfrage auf '$sitename' bestätigt.
diff --git a/view/de/lostpass_eml.tpl b/view/de/lostpass_eml.tpl
index 91b9b4c50..4c06d0c8d 100755
--- a/view/de/lostpass_eml.tpl
+++ b/view/de/lostpass_eml.tpl
@@ -1,5 +1,5 @@
-Lieber $username,
+Liebe/r $username,
wir haben gerade eine Anfrage erhalten dein Passwort auf $sitename zu ändern.
Um diese Anfrage zu bestätigen folge bitte dem Bestätigungslink oder kopiere
ihn in die Adresszeile deines Browsers.
diff --git a/view/de/passchanged_eml.tpl b/view/de/passchanged_eml.tpl
index 894fd4e88..d5e8d9048 100755
--- a/view/de/passchanged_eml.tpl
+++ b/view/de/passchanged_eml.tpl
@@ -1,5 +1,5 @@
-Lieber $username,
+Liebe/r $username,
dein Passwort wurde wie gewünscht geändert. Bitte hebe diese Informationen
für deine Unterlagen auf (oder ändere das Passwort augenblicklich in etwas
das du dir merken kannst).
diff --git a/view/de/register_open_eml.tpl b/view/de/register_open_eml.tpl
index ab7fed18c..d27c3c743 100755
--- a/view/de/register_open_eml.tpl
+++ b/view/de/register_open_eml.tpl
@@ -1,5 +1,5 @@
-Lieber $username,
+Liebe/r $username,
danke für die Registrierung bei $sitename. Dein neuer Account wurde angelegt.
Die Anmeldedetails sind die Folgenden.
diff --git a/view/de/request_notify_eml.tpl b/view/de/request_notify_eml.tpl
index 15b83f64f..55fa98e96 100755
--- a/view/de/request_notify_eml.tpl
+++ b/view/de/request_notify_eml.tpl
@@ -1,5 +1,5 @@
-Lieber $myname,
+Liebe/r $myname,
du hast gerade eine Kontaktanfrage von '$requestor' auf $sitename erhalten.
diff --git a/view/theme/vier/calendar.png b/view/theme/vier/calendar.png
new file mode 100755
index 000000000..705a75b8a
--- /dev/null
+++ b/view/theme/vier/calendar.png
Binary files differ
diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css
index 96233c1da..89dd98146 100644
--- a/view/theme/vier/style.css
+++ b/view/theme/vier/style.css
@@ -122,6 +122,17 @@
.next { background-position: -110px -60px;}
.tagged { background-position: -130px -60px;}
+.attachtype {
+ display: block; width: 20px; height: 23px;
+ background-image: url('../../../images/content-types.png');
+}
+
+.type-video { background-position: 0px 0px; }
+.type-image { background-position: -20px 0px; }
+.type-audio { background-position: -40px 0px; }
+.type-text { background-position: -60px 0px; }
+.type-unkn { background-position: -80px 0px; }
+
.icon.drop, .icon.drophide {
float: left;
}
@@ -200,9 +211,9 @@
.icon.s16.delete {
background-image: url("../../../images/icons/16/delete.png");
}
-.icon.s16.edit {
+/*.icon.s16.edit {
background-image: url("../../../images/icons/16/edit.png");
-}
+}*/
.icon.s16.star {
background-image: url("../../../images/icons/16/star.png");
}
@@ -913,7 +924,7 @@ section {
}
.wall-item-container .wall-item-actions-tools {
float: right;
- width: 60px;
+ width: 80px;
}
.wall-item-container .wall-item-actions-tools a {
float: right;
@@ -1028,7 +1039,13 @@ section {
/* contacts menu */
.contact-photo-wrapper {
position: relative;
+ width: 80px;
+}
+
+.contact-photo-wrapper.wwto {
+ width: 25px;
}
+
.contact-photo {
width: 48px;
height: 48px;
@@ -1390,9 +1407,34 @@ ul.tabs li .active {
.field.radio .field_help {
margin-left: 0px;
}
+
+#profile-edit-links-end {
+ clear: both;
+ margin-bottom: 15px;
+}
+
+#profile-edit-links ul { margin: 20px; padding-bottom: 20px; list-style: none; }
+
#profile-edit-links li {
+ float: left;
list-style: none;
+ margin-left: 10px;
}
+
+.profile-edit-side-div {
+ display: none;
+}
+
+#register-form label,
+#profile-edit-form label {
+ width: 300px; float: left;
+}
+
+.required {
+ display: inline;
+ color: #B20202;
+}
+
/* oauth */
.oauthapp {
height: auto;
@@ -1449,3 +1491,433 @@ footer {
height: 100px;
display: table-row;
}
+
+blockquote {
+ border-left: 1px solid #D2D2D2;
+ padding-left: 9px;
+ margin: 0 0 0 .8ex;
+}
+
+/* ================== */
+/* = Contacts Block = */
+/* ================== */
+
+.contact-block-img {
+ width: 42px;
+ height: 42px;
+ padding-right: 2px;
+}
+.contact-block-div {
+ float: left;
+}
+
+.contact-block-textdiv { width: 150px; height: 34px; float: left; }
+#contact-block-end { clear: both; }
+
+#group-edit-wrapper {
+ margin-bottom: 10px;
+}
+
+#group-members-end {
+ clear: both;
+}
+
+/*
+#group-separator,
+#prof-separator { display: none;}
+*/
+
+#prvmail-wrapper, .mail-conv-detail, .mail-list-detail {
+ position: relative;
+ width: 500px;
+ padding: 50px;
+ margin: 20px auto;
+ background-color: #fff;
+ -webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);
+}
+
+#prvmail-wrapper:before, #prvmail-wrapper:after, .mail-conv-detail:before, .mail-conv-detail:after, .mail-list-detail:before, .mail-list-detail:after {
+ position: absolute;
+ width: 40%;
+ height: 10px;
+ content: ' ';
+ left: 12px;
+ bottom: 12px;
+ background: transparent;
+ -webkit-transform: skew(-5deg) rotate(-5deg);
+ -moz-transform: skew(-5deg) rotate(-5deg);
+ -ms-transform: skew(-5deg) rotate(-5deg);
+ -o-transform: skew(-5deg) rotate(-5deg);
+ transform: skew(-5deg) rotate(-5deg);
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
+ z-index: -1;
+}
+
+#prvmail-wrapper:after, .mail-conv-detail:after, .mail-list-detail:after {
+ left: auto;
+ right: 12px;
+ -webkit-transform: skew(5deg) rotate(5deg);
+ -moz-transform: skew(5deg) rotate(5deg);
+ -ms-transform: skew(5deg) rotate(5deg);
+ -o-transform: skew(5deg) rotate(5deg);
+ transform: skew(5deg) rotate(5deg);
+}
+
+.prvmail-text {
+ width: 100%;
+}
+
+.mail-list-outside-wrapper {
+ margin-top: 20px;
+}
+
+.mail-list-sender {
+ float: left;
+ padding: 5px;
+ background-color: #efefef;
+ border: 2px dotted #eeeeee;
+ -moz-box-shadow: 3px 3px 4px #959494;
+ -webkit-box-shadow: 3px 3px 4px #959494;
+ box-shadow: 3px 3px 4px #959494;
+}
+
+.mail-list-detail {
+ margin-left: 100px;
+ width: 300px;
+ min-height: 70px;
+ padding: 20px;
+ padding-top:10px;
+ border: 1px solid #dddddd;
+ }
+
+.mail-list-sender-name {
+ font-size: 1.1em;
+ display: inline;
+ font-variant:small-caps;
+}
+
+.mail-list-date {
+ float: right;
+ clear: block;
+ display: inline;
+ font-size: 0.9em;
+ padding-left: 10px;
+ font-stretch:ultra-condensed;
+ font-variant:small-caps;
+}
+
+.mail-list-subject {
+ clear: block;
+ font-size: 1.2em;
+ padding-top: 20px;
+ padding-right: 50px;
+}
+
+.mail-list-subject a {
+ color: #626262;
+}
+
+.mail-list-delete-wrapper { float: right;}
+.mail-list-outside-wrapper-end {
+ clear: both;
+}
+
+.mail-conv-outside-wrapper {
+ margin-bottom: 10px;
+}
+
+.mail-conv-sender {float: left; margin: 0px 5px 5px 0px; }
+.mail-conv-sender-photo {
+ width: 64px;
+ height: 64px;
+}
+
+.mail-conv-sender-name { float: left; font-variant:small-caps; font-style: bold; }
+.mail-conv-date { float: right; font-variant:small-caps; }
+.mail-conv-subject { clear: right; font-weight: bold; font-size: 1.2em }
+.mail-conv-body {
+ clear: both;
+}
+
+.mail-conv-detail {
+ width: 500px;
+ padding: 30px;
+ padding-bottom: 10px;
+ margin-left: 20px;
+ margin-bottom: 0px;
+ vertical-align: middle;
+ margin: auto;
+ border: 1px solid #dddddd;
+}
+.mail-conv-break { display: none; border: none;}
+.mail-conv-delete-wrapper { padding-top: 10px; width: 510px; text-align: right; }
+
+/* ========== */
+/* = Events = */
+/* ========== */
+
+.clear { clear: both; }
+.eventcal {
+ float: left;
+ font-size: 20px;
+ padding: 20px;
+}
+
+.vevent {
+ position: relative;
+ width: 400px;
+ padding: 20px;
+ padding-top: 10px;
+ margin: 0 0px;
+ margin-bottom: 10px;
+ background-color: #fff;
+ -webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);
+}
+
+.vevent:before, .vevent:after {
+ position: absolute;
+ width: 40%;
+ height: 10px;
+ content: ' ';
+ left: 12px;
+ bottom: 12px;
+ background: transparent;
+ -webkit-transform: skew(-5deg) rotate(-5deg);
+ -moz-transform: skew(-5deg) rotate(-5deg);
+ -ms-transform: skew(-5deg) rotate(-5deg);
+ -o-transform: skew(-5deg) rotate(-5deg);
+ transform: skew(-5deg) rotate(-5deg);
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
+ z-index: -1;
+}
+
+.vevent:after {
+ left: auto;
+ right: 12px;
+ -webkit-transform: skew(5deg) rotate(5deg);
+ -moz-transform: skew(5deg) rotate(5deg);
+ -ms-transform: skew(5deg) rotate(5deg);
+ -o-transform: skew(5deg) rotate(5deg);
+ transform: skew(5deg) rotate(5deg);
+}
+
+.vevent .event-description {
+ margin-left: 10px;
+ margin-right: 10px;
+ text-align:center;
+ font-size: 1.2em;
+ font-weight:bolder;
+}
+
+ .vevent .event-location{
+ margin-left: 10px;
+ margin-right: 10px;
+ font-size: 1em;
+ font-style: oblique;
+ text-align: center;
+
+}
+
+.vevent .event-start, .vevent .event-end {
+ margin-left: 20px;
+ margin-right: 20px;
+ margin-bottom: 2px;
+ margin-top: 2px;
+ font-size: 0.9em;
+ font-variant: small-caps;
+ text-align: left;
+}
+
+#new-event-link{
+ width: 130px;
+ padding: 7px;
+ margin-bottom: 10px;
+ margin-left: 170px; ;
+ -moz-box-shadow:inset 0px 1px 0px 0px #cfcfcf;
+ -webkit-box-shadow:inset 0px 1px 0px 0px #cfcfcf;
+ box-shadow:inset 0px 1px 0px 0px #cfcfcf;
+ background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #bdbdbd), color-stop(1, #a2a2a2) );
+ background:-moz-linear-gradient( center top, #bdbdbd 5%, #a2a2a2 100% );
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#bdbdbd', endColorstr='#a2a2a2');
+ background-color:#bdbdbd;
+ -moz-border-radius:5px;
+ -webkit-border-radius:5px;
+ border-radius:5px;
+ color: #efefef;
+}
+
+#new-event-link:hover {
+ color: #efefef;
+ background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #b20202), color-stop(1, #d60808) );
+ background:-moz-linear-gradient( center top, #b20202 5%, #d60808 100% );
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#b20202', endColorstr='#d60808');
+ background-color:#b20202;
+}
+
+#new-event-link:active {
+ background-color: #b20202;
+ position:relative;
+ top:1px;
+}
+
+#new-event-link a {
+ color: #efefef;
+ text-align: center;
+}
+
+.edit-event-link, .plink-event-link {
+ float: left;
+ margin-top: 4px;
+ margin-right: 4px;
+ margin-bottom: 15px;
+}
+
+.event-description:before {
+ content: url('calendar.png');
+ margin-right: 15px;
+ vertical-align: middle;
+}
+
+.event-start, .event-end {
+ margin-left: 10px;
+ width: 330px;
+}
+
+.event-start .dtstart, .event-end .dtend {
+ float: right;
+}
+
+.event-list-date {
+ color: #626262;
+ margin-bottom: 10px;
+ font-variant:small-caps;
+ font-stretch:condensed;
+}
+
+.prevcal, .nextcal {
+ float: left;
+ margin-left: 32px;
+ margin-right: 32px;
+ margin-top: 64px;
+}
+
+.event-calendar-end {
+ clear: both;
+}
+
+.calendar {
+ width: 300px;
+ font-family: Helvetica, Arial, sans-serif;
+ background-color: #f1f1f1;
+ border: 1px solid #dedede;
+ margin-bottom: 10px;
+ -moz-box-shadow: 5px 5px 8px #959494;
+ -webkit-box-shadow: 5px 5px 8px #959494;
+ box-shadow: 5px 5px 8px #959494;
+}
+
+.calendar caption{
+ background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #d60808), color-stop(1, #b20202) );
+ background:-moz-linear-gradient( center top, #d60808 5%, #b20202 100% );
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d60808', endColorstr='#b20202');
+ background-color: #b20202;
+ padding: 10px 0px 10px 0px;
+ width: 300px;
+ color: #ffffff;
+ font-weight: bold;
+ text-align:center;
+ font-variant:small-caps;
+ -moz-box-shadow: 5px 2px 8px #959494;
+ -webkit-box-shadow: 5px 2px 8px #959494;
+ box-shadow: 5px 2px 8px #959494;
+}
+
+tr {
+ border: 1px solid #eeeeee;
+}
+
+.calendar td {
+ font-size: 14px;
+ text-align: center;
+ padding: 3px 0px;
+}
+
+.calendar td > a {
+ background-color: #cdcdcd;
+ padding: 2px;
+ color: #000;
+}
+
+.calendar th {
+ font-size: 16px;
+}
+
+.today {
+ font-weight: bold;
+ text-align: center;
+ background-color: #b20202;
+ color: #fff;
+}
+
+#event-start-text,
+#event-finish-text {
+ margin-top: 10px;
+ margin-bottom: 5px;
+}
+
+#event-nofinish-checkbox,
+#event-nofinish-text,
+#event-adjust-checkbox,
+#event-adjust-text,
+#event-share-checkbox {
+ float: left;
+}
+
+#event-datetime-break {
+ margin-bottom: 10px;
+}
+
+#event-nofinish-break,
+#event-adjust-break,
+#event-share-break {
+ clear: both;
+}
+
+#event-desc-text,
+#event-location-text {
+ margin-top: 10px;
+ margin-bottom: 5px;
+}
+
+#event-submit {
+ margin-top: 10px;
+}
+
+/* ============= */
+/* = Directory = */
+/* ============= */
+
+.directory-item {
+ float: left;
+ margin: 50px 50px 0px 0px;
+}
+
+.directory-details {
+ font-size: 0.9em;
+ font-variant: small-caps;
+ width: 160px;
+}
+
+.directory-name {
+ font-size: 1em;
+ font-variant: small-caps;
+ width: 150px;
+}