aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Daemon/Notifier.php2
-rw-r--r--Zotlabs/Lib/Apps.php1
-rw-r--r--Zotlabs/Module/Cards.php189
-rw-r--r--Zotlabs/Widget/Categories.php13
-rw-r--r--app/cards.apd5
-rw-r--r--include/contact_widgets.php43
-rw-r--r--include/conversation.php16
-rw-r--r--include/features.php9
-rw-r--r--include/nav.php12
-rw-r--r--include/taxonomy.php76
-rw-r--r--view/pdl/mod_cards.pdl2
-rw-r--r--view/tpl/cards.tpl8
-rwxr-xr-xview/tpl/jot.tpl4
13 files changed, 373 insertions, 7 deletions
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index 33dcbbf20..e8cd4dac8 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -276,7 +276,7 @@ class Notifier {
$deleted_item = true;
}
- if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST, ITEM_TYPE_CARD ] )) {
+ if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return;
}
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index 3730f3a23..37cbf9497 100644
--- a/Zotlabs/Lib/Apps.php
+++ b/Zotlabs/Lib/Apps.php
@@ -221,6 +221,7 @@ class Apps {
static public function translate_system_apps(&$arr) {
$apps = array(
'Apps' => t('Apps'),
+ 'Cards' => t('Cards'),
'Site Admin' => t('Site Admin'),
'Report Bug' => t('Report Bug'),
'View Bookmarks' => t('View Bookmarks'),
diff --git a/Zotlabs/Module/Cards.php b/Zotlabs/Module/Cards.php
new file mode 100644
index 000000000..1fdd3b63f
--- /dev/null
+++ b/Zotlabs/Module/Cards.php
@@ -0,0 +1,189 @@
+<?php
+namespace Zotlabs\Module;
+
+require_once('include/channel.php');
+require_once('include/conversation.php');
+require_once('include/acl_selectors.php');
+
+
+class Cards extends \Zotlabs\Web\Controller {
+
+ function init() {
+
+ if(argc() > 1)
+ $which = argv(1);
+ else
+ return;
+
+ profile_load($which);
+
+ }
+
+
+ function get() {
+
+ if(observer_prohibited(true)) {
+ return login();
+ }
+
+ if(! \App::$profile) {
+ notice( t('Requested profile is not available.') . EOL );
+ \App::$error = 404;
+ return;
+ }
+
+ if(! feature_enabled(\App::$profile_uid,'cards')) {
+ return;
+ }
+
+ nav_set_selected(t('Cards'));
+
+ $category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : '');
+
+ if($category) {
+ $sql_extra2 .= protect_sprintf(term_item_parent_query(\App::$profile['profile_uid'],'item', $category, TERM_CATEGORY));
+ }
+
+
+ $which = argv(1);
+
+ $_SESSION['return_url'] = \App::$query_string;
+
+ $uid = \App::$profile_uid;
+ $owner = 0;
+ $observer = \App::get_observer();
+
+ $channel = \App::$profile;
+
+ if(! $owner) {
+ // Figure out who the page owner is.
+ $r = q("select channel_id from channel where channel_address = '%s'",
+ dbesc($which)
+ );
+ if($r) {
+ $owner = intval($r[0]['channel_id']);
+ }
+ }
+
+ $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
+
+ if(! perm_is_allowed($owner,$ob_hash,'view_pages')) {
+ notice( t('Permission denied.') . EOL);
+ return;
+ }
+
+ $mimetype = (($_REQUEST['mimetype']) ? $_REQUEST['mimetype'] : get_pconfig($owner,'system','page_mimetype'));
+
+ $layout = (($_REQUEST['layout']) ? $_REQUEST['layout'] : get_pconfig($owner,'system','page_layout'));
+
+ // Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages
+ // Nickname is set to the observers xchan, and profile_uid to the owner's.
+ // This lets you post pages at other people's channels.
+
+ if((! $channel) && ($uid) && ($uid == \App::$profile_uid)) {
+ $channel = \App::get_channel();
+ }
+ if($channel) {
+ $channel_acl = array(
+ 'allow_cid' => $channel['channel_allow_cid'],
+ 'allow_gid' => $channel['channel_allow_gid'],
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid']
+ );
+ }
+ else {
+ $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
+ }
+
+
+ $is_owner = ($uid && $uid == $owner);
+
+ if(perm_is_allowed($owner,$ob_hash,'write_pages')) {
+
+ $x = array(
+ 'webpage' => ITEM_TYPE_CARD,
+ 'is_owner' => true,
+ 'nickname' => \App::$profile['channel_address'],
+ 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
+ 'acl' => (($is_owner) ? populate_acl($channel_acl,false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')) : ''),
+ 'permissions' => $channel_acl,
+ 'showacl' => (($is_owner) ? true : false),
+ 'visitor' => true,
+ 'hide_location' => true,
+ 'hide_voting' => true,
+ 'profile_uid' => intval($owner),
+ 'mimetype' => $mimetype,
+ 'mimeselect' => false,
+ 'layoutselect' => false,
+ 'expanded' => false,
+ 'novoting'=> true,
+ 'bbco_autocomplete' => 'bbcode',
+ 'bbcode' => true
+ );
+ }
+ else {
+ $x = '';
+ }
+
+ if($_REQUEST['title'])
+ $x['title'] = $_REQUEST['title'];
+ if($_REQUEST['body'])
+ $x['body'] = $_REQUEST['body'];
+
+ // Get a list of webpages. We can't display all them because endless scroll makes that unusable,
+ // so just list titles and an edit link.
+
+
+ $sql_extra = item_permissions_sql($owner);
+
+ $r = q("select * from item
+ where item.uid = %d and item_type = %d
+ $sql_extra order by item.created desc",
+ intval($owner),
+ intval(ITEM_TYPE_CARD)
+ );
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+
+
+ if($x)
+ $editor = status_editor($a,$x);
+
+ if($r) {
+
+ $parents_str = ids_to_querystr($r,'id');
+
+ $items = q("SELECT item.*, item.id AS item_id
+ FROM item
+ WHERE item.uid = %d $item_normal
+ AND item.parent IN ( %s )
+ $sql_extra $sql_extra2 ",
+ intval(\App::$profile['profile_uid']),
+ dbesc($parents_str)
+ );
+ if($items) {
+ xchan_query($items);
+ $items = fetch_post_tags($items, true);
+ $items = conv_sort($items,'created');
+ }
+ else
+ $items = [];
+ }
+
+ $mode = 'channel';
+
+ $content = conversation($items,$mode,false,'traditional');
+
+ $o = replace_macros(get_markup_template('cards.tpl'), [
+ '$title' => t('Cards'),
+ '$editor' => $editor,
+ '$content' => $content,
+ '$pager' => alt_pager($a,count($items))
+ ]);
+
+ return $o;
+ }
+
+}
diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php
index d1dcfda93..a11b3d919 100644
--- a/Zotlabs/Widget/Categories.php
+++ b/Zotlabs/Widget/Categories.php
@@ -8,8 +8,13 @@ class Categories {
function widget($arr) {
+ $cards = ((array_key_exists('cards',$arr) && $arr['cards']) ? true : false);
+
+ if(($cards) && (! feature_enabled(\App::$profile['profile_uid'],'cards'))
+ return '';
+
if((! \App::$profile['profile_uid'])
- || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),'view_stream'))) {
+ || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),(($cards) ? 'view_pages' : 'view_stream')))) {
return '';
}
@@ -18,6 +23,10 @@ class Categories {
$srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&');
$srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl);
- return categories_widget($srchurl, $cat);
+ if($cards)
+ return cardcategories_widget($srchurl, $cat);
+ else
+ return categories_widget($srchurl, $cat);
+
}
}
diff --git a/app/cards.apd b/app/cards.apd
new file mode 100644
index 000000000..4577dd681
--- /dev/null
+++ b/app/cards.apd
@@ -0,0 +1,5 @@
+version: 1
+url: $baseurl/cards/$nick
+name: Cards
+photo: icon:list
+categories: Productivity
diff --git a/include/contact_widgets.php b/include/contact_widgets.php
index 8f76bb4bc..aac756a46 100644
--- a/include/contact_widgets.php
+++ b/include/contact_widgets.php
@@ -100,6 +100,49 @@ function categories_widget($baseurl,$selected = '') {
return '';
}
+function cardcategories_widget($baseurl,$selected = '') {
+
+ if(! feature_enabled(App::$profile['profile_uid'],'categories'))
+ return '';
+
+ $item_normal = "and item.item_hidden = 0 and item.item_type = 6 and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+
+ $terms = array();
+ $r = q("select distinct(term.term)
+ from term join item on term.oid = item.id
+ where item.uid = %d
+ and term.uid = item.uid
+ and term.ttype = %d
+ and term.otype = %d
+ and item.owner_xchan = '%s'
+ $item_normal
+ order by term.term asc",
+ intval(App::$profile['profile_uid']),
+ intval(TERM_CATEGORY),
+ intval(TERM_OBJ_POST),
+ dbesc(App::$profile['channel_hash'])
+ );
+ if($r && count($r)) {
+ foreach($r as $rr)
+ $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : ''));
+
+ return replace_macros(get_markup_template('categories_widget.tpl'),array(
+ '$title' => t('Categories'),
+ '$desc' => '',
+ '$sel_all' => (($selected == '') ? 'selected' : ''),
+ '$all' => t('Everything'),
+ '$terms' => $terms,
+ '$base' => $baseurl,
+
+ ));
+ }
+ return '';
+}
+
+
+
function common_friends_visitor_widget($profile_uid) {
if(local_channel() == $profile_uid)
diff --git a/include/conversation.php b/include/conversation.php
index 3b8ec19d3..c9142ac30 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -1835,7 +1835,8 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
require_once('include/menu.php');
$has_bookmarks = menu_list_count(local_channel(),'',MENU_BOOKMARK) + menu_list_count(local_channel(),'',MENU_SYSTEM|MENU_BOOKMARK);
- if ($is_owner && $has_bookmarks) {
+
+ if($is_owner && $has_bookmarks) {
$tabs[] = array(
'label' => t('Bookmarks'),
'url' => z_root() . '/bookmarks',
@@ -1846,6 +1847,17 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
);
}
+ if(feature_enabled($uid,'cards')) {
+ $tabs[] = array(
+ 'label' => t('Cards'),
+ 'url' => z_root() . '/cards/' . $nickname,
+ 'sel' => ((argv(0) == 'cards') ? 'active' : ''),
+ 'title' => t('View Cards'),
+ 'id' => 'cards-tab',
+ 'icon' => 'list'
+ );
+ }
+
if($has_webpages && feature_enabled($uid,'webpages')) {
$tabs[] = array(
'label' => t('Webpages'),
@@ -1856,7 +1868,7 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
'icon' => 'newspaper-o'
);
}
-
+
if ($p['view_wiki']) {
if(feature_enabled($uid,'wiki') && (get_account_techlevel($account_id) > 3)) {
diff --git a/include/features.php b/include/features.php
index f32dbe82e..f84c9cb05 100644
--- a/include/features.php
+++ b/include/features.php
@@ -118,6 +118,15 @@ function get_features($filtered = true) {
],
[
+ 'cards',
+ t('Cards'),
+ t('Create personal planning cards'),
+ false,
+ get_config('feature_lock','cards'),
+ feature_level('cards',1),
+ ],
+
+ [
'nav_channel_select',
t('Navigation Channel Select'),
t('Change channels directly from within the navigation dropdown menu'),
diff --git a/include/nav.php b/include/nav.php
index 76a8f8fb9..f5a1236a8 100644
--- a/include/nav.php
+++ b/include/nav.php
@@ -434,6 +434,18 @@ function channel_apps($is_owner = false, $nickname = null) {
];
}
+ if($p['view_pages'] && feature_enabled($uid,'cards')) {
+ $tabs[] = [
+ 'label' => t('Cards'),
+ 'url' => z_root() . '/cards/' . $nickname ,
+ 'sel' => ((argv(0) == 'cards') ? 'active' : ''),
+ 'title' => t('View Cards'),
+ 'id' => 'cards-tab',
+ 'icon' => 'list'
+ ];
+ }
+
+
if($has_webpages && feature_enabled($uid,'webpages')) {
$tabs[] = [
'label' => t('Webpages'),
diff --git a/include/taxonomy.php b/include/taxonomy.php
index 46d661581..36e05b008 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -199,6 +199,62 @@ function tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0, $re
}
+
+
+function card_tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0, $restrict = 0, $type = TERM_CATEGORY) {
+
+ require_once('include/security.php');
+
+ if(! perm_is_allowed($uid,get_observer_hash(),'view_pages'))
+ return array();
+
+
+ $item_normal = item_normal();
+ $sql_options = item_permissions_sql($uid);
+ $count = intval($count);
+
+ if($flags) {
+ if($flags === 'wall')
+ $sql_options .= " and item_wall = 1 ";
+ }
+
+ if($authors) {
+ if(! is_array($authors))
+ $authors = array($authors);
+
+ stringify_array_elms($authors,true);
+ $sql_options .= " and author_xchan in (" . implode(',',$authors) . ") ";
+ }
+
+ if($owner) {
+ $sql_options .= " and owner_xchan = '" . dbesc($owner) . "' ";
+ }
+
+
+ // Fetch tags
+ $r = q("select term, count(term) as total from term left join item on term.oid = item.id
+ where term.uid = %d and term.ttype = %d
+ and otype = %d and item_type = %d and item_private = 0
+ $sql_options $item_normal
+ group by term order by total desc %s",
+ intval($uid),
+ intval($type),
+ intval(TERM_OBJ_POST),
+ intval($restrict),
+ ((intval($count)) ? "limit $count" : '')
+ );
+
+ if(! $r)
+ return array();
+
+ return Zotlabs\Text\Tagadelic::calc($r);
+
+}
+
+
+
+
+
function dir_tagadelic($count = 0) {
$count = intval($count);
@@ -316,6 +372,26 @@ function catblock($uid,$count = 0,$authors = '',$owner = '', $flags = 0,$restric
return $o;
}
+function card_catblock($uid,$count = 0,$authors = '',$owner = '', $flags = 0,$restrict = 0,$type = TERM_CATEGORY) {
+ $o = '';
+
+ $r = card_tagadelic($uid,$count,$authors,$owner,$flags,$restrict,$type);
+
+ if($r) {
+ $c = q("select channel_address from channel where channel_id = %d limit 1",
+ intval($uid)
+ );
+
+ $o = '<div class="tagblock widget"><h3>' . t('Categories') . '</h3><div class="tags" align="center">';
+ foreach($r as $rr) {
+ $o .= '<a href="cards/' . $c[0]['channel_address']. '?f=&cat=' . urlencode($rr[0]).'" class="tag'.$rr[2].'">'.$rr[0].'</a> ' . "\r\n";
+ }
+ $o .= '</div></div>';
+ }
+
+ return $o;
+}
+
function dir_tagblock($link,$r) {
$o = '';
diff --git a/view/pdl/mod_cards.pdl b/view/pdl/mod_cards.pdl
new file mode 100644
index 000000000..2d87136c9
--- /dev/null
+++ b/view/pdl/mod_cards.pdl
@@ -0,0 +1,2 @@
+[region=aside]
+[widget=categories][var=cards]1[/var][/widget][/region]
diff --git a/view/tpl/cards.tpl b/view/tpl/cards.tpl
new file mode 100644
index 000000000..ae382a97f
--- /dev/null
+++ b/view/tpl/cards.tpl
@@ -0,0 +1,8 @@
+<div class="generic-content-wrapper">
+ <div class="section-title-wrapper">
+ <h2>{{$title}}</h2>
+ </div>
+ {{$editor}}
+ {{$content}}
+</div>
+ {{$pager}}
diff --git a/view/tpl/jot.tpl b/view/tpl/jot.tpl
index 39ba9e59b..8e8070402 100755
--- a/view/tpl/jot.tpl
+++ b/view/tpl/jot.tpl
@@ -27,7 +27,7 @@
<input type="hidden" id="jot-consensus" name="consensus" value="{{if $consensus}}{{$consensus}}{{else}}0{{/if}}" />
<input type="hidden" id="jot-nocomment" name="nocomment" value="{{if $nocomment}}{{$nocomment}}{{else}}0{{/if}}" />
- {{if $webpage}}
+ {{if $webpage && $webpage != 6 }}
<div id="jot-pagetitle-wrap" class="jothidden">
<input name="pagetitle" id="jot-pagetitle" type="text" placeholder="{{$placeholdpagetitle}}" value="{{$pagetitle}}">
</div>
@@ -35,7 +35,7 @@
<div id="jot-title-wrap" class="jothidden">
<input name="title" id="jot-title" type="text" placeholder="{{$placeholdertitle}}" tabindex="1" value="{{$title}}">
</div>
- {{if $catsenabled}}
+ {{if $catsenabled || $webpage == 6 }}
<div id="jot-category-wrap" class="jothidden">
<input name="category" id="jot-category" type="text" placeholder="{{$placeholdercategory}}" value="{{$category}}" data-role="cat-tagsinput">
</div>