]> git.mxchange.org Git - friendica.git/commitdiff
Merge pull request #7901 from annando/disable-smart-threading
authorHypolite Petovan <hypolite@mrpetovan.com>
Wed, 4 Dec 2019 20:25:53 +0000 (15:25 -0500)
committerGitHub <noreply@github.com>
Wed, 4 Dec 2019 20:25:53 +0000 (15:25 -0500)
Changed the option to enable the smart threading with the option to disable this

66 files changed:
.drone.yml
.travis.yml
bin/dev/minifyjs.sh
include/api.php
mod/community.php
mod/display.php
mod/events.php
mod/network.php
mod/photos.php
mod/settings.php
src/App/Page.php
src/Content/Text/BBCode.php
src/Core/ACL.php
src/Core/System.php
src/Core/Theme.php
src/Model/Group.php
src/Module/Bookmarklet.php
src/Module/Contact.php
src/Module/Item/Compose.php
src/Module/Item/Ignore.php
src/Module/NodeInfo.php
src/Module/Objects.php
src/Module/Profile.php
src/Module/WellKnown/NodeInfo.php [new file with mode: 0644]
src/Object/Post.php
src/Protocol/ActivityPub/Transmitter.php
static/defaults.config.php
static/routes.config.php
tests/include/ApiTest.php
view/js/acl.js [deleted file]
view/js/friendica-tagsinput/LICENSE [new file with mode: 0644]
view/js/friendica-tagsinput/friendica-tagsinput-typeahead.css [new file with mode: 0644]
view/js/friendica-tagsinput/friendica-tagsinput.css [new file with mode: 0644]
view/js/friendica-tagsinput/friendica-tagsinput.js [new file with mode: 0644]
view/js/linkPreview.js
view/js/main.js
view/templates/acl_selector.tpl
view/templates/head.tpl
view/templates/item/compose-footer.tpl [deleted file]
view/templates/item/compose.tpl
view/theme/duepuntozero/deriv/darkzero.css
view/theme/duepuntozero/style.css
view/theme/frio/css/style.css
view/theme/frio/frameworks/friendica-tagsinput/LICENSE [deleted file]
view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput-typeahead.css [deleted file]
view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.css [deleted file]
view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.js [deleted file]
view/theme/frio/js/compose.js [new file with mode: 0644]
view/theme/frio/js/event_edit.js
view/theme/frio/js/modal.js
view/theme/frio/php/standard.php
view/theme/frio/scheme/plusminus.css
view/theme/frio/templates/acl_selector.tpl [deleted file]
view/theme/frio/templates/event_form.tpl
view/theme/frio/templates/filebrowser.tpl
view/theme/frio/templates/head.tpl
view/theme/frio/templates/jot.tpl
view/theme/quattro/dark/style.css
view/theme/quattro/green/style.css
view/theme/quattro/lilac/style.css
view/theme/quattro/quattro.less
view/theme/smoothly/style.css
view/theme/smoothly/templates/jot.tpl
view/theme/vier/dark.css
view/theme/vier/mobile.css
view/theme/vier/style.css

index ada824ab5eb40b8242de736f99395518aa0ee942..887ccfdf0a1f6e0bc6a65dc4036bc3d77b41aaa2 100644 (file)
@@ -24,7 +24,7 @@ services:
     MYSQL_USER: friendica
     MYSQL_PASSWORD: friendica
     MYSQL_DATABASE: friendica
-  volumes: 
+  volumes:
     - name: cache
       path: /var/lib/mysql
 
@@ -34,12 +34,12 @@ volumes:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: mysql8.0-php7.2
@@ -77,12 +77,12 @@ volumes:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: mysql8.0-php7.3
@@ -120,12 +120,12 @@ volumes:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: mariadb10.1-php7.1
@@ -167,12 +167,12 @@ volumes:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: mariadb10.1-php7.2
@@ -209,12 +209,12 @@ volumes:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: mariadb10.1-php7.3
@@ -249,6 +249,14 @@ volumes:
   - name: cache
     temp: {}
 
+trigger:
+  branch:
+#    - master
+    - develop
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: redis-php7.1
@@ -272,12 +280,12 @@ services:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: redis-php7.2
@@ -296,12 +304,12 @@ services:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: redis-php7.3
@@ -318,6 +326,15 @@ services:
 - name: redis
   image: redis
 
+trigger:
+  branch:
+#    - master
+    - develop
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
+
 ---
 kind: pipeline
 name: memcache-php7.1
@@ -341,12 +358,12 @@ services:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: memcache-php7.2
@@ -365,12 +382,12 @@ services:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: memcache-php7.3
@@ -387,6 +404,16 @@ services:
 - name: memcached
   image: memcached
 
+trigger:
+  branch:
+#    - master
+    - develop
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
+
+
 ---
 kind: pipeline
 name: memcached-php7.1
@@ -410,12 +437,12 @@ services:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: memcached-php7.2
@@ -434,12 +461,12 @@ services:
 
 trigger:
   branch:
-    - master
+#    - master
     - develop
-    - "*-rc"
-  event:
-    - pull_request
-    - push
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
 ---
 kind: pipeline
 name: memcached-php7.3
@@ -455,3 +482,12 @@ steps:
 services:
 - name: memcached
   image: memcached
+
+trigger:
+  branch:
+#    - master
+    - develop
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
index 95333b6c9e5188d8271cc8b5a9afe7063ded2438..e306787ff16af3fc3e31c027f86a6d3cbcba1618 100644 (file)
@@ -24,4 +24,6 @@ before_script:
  - phpenv config-add .travis/redis.ini
  - phpenv config-add .travis/memcached.ini
 
-script: vendor/bin/phpunit --configuration tests/phpunit.xml
+script: vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-clover clover.xml
+
+after_success: bash <(curl -s https://codecov.io/bash)
index 50a56a45ca52fd79fa8d1a802cdb11b443933745..caa2b3846a4d8b7809d2367a708b7388d9015209 100755 (executable)
@@ -5,16 +5,13 @@ command -v uglifyjs >/dev/null 2>&1 || { echo >&2 "I require UglifyJS but it's n
 MINIFY_CMD=uglifyjs
 
 JSFILES=(
-       "view/js/acl.js"
        "view/js/ajaxupload.js"
        "view/js/country.js"
        "view/js/main.js"
        "vendor/asset/base64/base64.min.js"
-       "view/theme/frost/js/acl.js"
        "view/theme/frost/js/jquery.divgrow-1.3.1.f1.js"
        "view/theme/frost/js/main.js"
        "view/theme/frost/js/theme.js"
-       "view/theme/frost-mobile/js/acl.js"
        "view/theme/frost-mobile/js/jquery.divgrow-1.3.1.f1.js"
        "view/theme/frost-mobile/js/main.js"
        "view/theme/frost-mobile/js/theme.js"
index 22fe64097bbafa8640f75df8f5c01d4661fc006e..27793ac2806cdb1e12eed840f51ddcb31c618bae 100644 (file)
@@ -2498,7 +2498,7 @@ function api_convert_item($item)
                $statustext = mb_substr($statustext, 0, 1000) . "... \n" . ($item['plink'] ?? '');
        }
 
-       $statushtml = BBCode::convert(api_clean_attachments($body), false);
+       $statushtml = BBCode::convert(BBCode::removeAttachment($body), false);
 
        // Workaround for clients with limited HTML parser functionality
        $search = ["<br>", "<blockquote>", "</blockquote>",
@@ -5409,42 +5409,11 @@ function api_clean_plain_items($text)
        }
 
        // Simplify "attachment" element
-       $text = api_clean_attachments($text);
+       $text = BBCode::removeAttachment($text);
 
        return $text;
 }
 
-/**
- * @brief Removes most sharing information for API text export
- *
- * @param string $body The original body
- *
- * @return string Cleaned body
- * @throws InternalServerErrorException
- */
-function api_clean_attachments($body)
-{
-       $data = BBCode::getAttachmentData($body);
-
-       if (empty($data)) {
-               return $body;
-       }
-       $body = "";
-
-       if (isset($data["text"])) {
-               $body = $data["text"];
-       }
-       if (($body == "") && isset($data["title"])) {
-               $body = $data["title"];
-       }
-       if (isset($data["url"])) {
-               $body .= "\n".$data["url"];
-       }
-       $body .= $data["after"];
-
-       return $body;
-}
-
 /**
  *
  * @param array $contacts
index 81857c6d3a0d64a3cacd78940a0864bf20edaf35..4d98f0c4fa24d6dabd74ad7097bb34e1b240f168 100644 (file)
@@ -125,7 +125,7 @@ function community_content(App $a, $update = 0)
                                'default_location' => $a->user['default-location'],
                                'nickname' => $a->user['nickname'],
                                'lockstate' => (is_array($a->user) && (strlen($a->user['allow_cid']) || strlen($a->user['allow_gid']) || strlen($a->user['deny_cid']) || strlen($a->user['deny_gid'])) ? 'lock' : 'unlock'),
-                               'acl' => ACL::getFullSelectorHTML($a->user, true),
+                               'acl' => ACL::getFullSelectorHTML($a->page, $a->user, true),
                                'bang' => '',
                                'visitor' => 'block',
                                'profile_uid' => local_user(),
index 12fa8d7ecefb9c320e71b641b2f0e9af216cc2d0..175616f98d9c4ef77a292773d67b95dbc0d25c80 100644 (file)
@@ -304,7 +304,7 @@ function display_content(App $a, $update = false, $update_uid = 0)
                        'default_location' => $a->user['default-location'],
                        'nickname' => $a->user['nickname'],
                        'lockstate' => (is_array($a->user) && (strlen($a->user['allow_cid']) || strlen($a->user['allow_gid']) || strlen($a->user['deny_cid']) || strlen($a->user['deny_gid'])) ? 'lock' : 'unlock'),
-                       'acl' => ACL::getFullSelectorHTML($a->user, true),
+                       'acl' => ACL::getFullSelectorHTML($a->page, $a->user, true),
                        'bang' => '',
                        'visitor' => 'block',
                        'profile_uid' => local_user(),
index 11bb25f51b9f8f8ec10e686e7f7a4ce9c2ee132e..5a5a22d3186bd194a079dc407966a30c7e7ef472 100644 (file)
@@ -13,6 +13,7 @@ use Friendica\Core\L10n;
 use Friendica\Core\Logger;
 use Friendica\Core\Renderer;
 use Friendica\Core\System;
+use Friendica\Core\Theme;
 use Friendica\Core\Worker;
 use Friendica\Database\DBA;
 use Friendica\Model\Event;
@@ -384,6 +385,12 @@ function events_content(App $a)
                        $events[$key]['item'] = $event_item;
                }
 
+               // ACL blocks are loaded in modals in frio
+               $a->page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
+               $a->page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));
+               $a->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
+               $a->page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
+
                $o = Renderer::replaceMacros($tpl, [
                        '$tabs'      => $tabs,
                        '$title'     => L10n::t('Events'),
@@ -483,10 +490,8 @@ function events_content(App $a)
                $fhour   = !empty($orig_event) ? DateTimeFormat::convert($fdt, $tz, 'UTC', 'H') : '00';
                $fminute = !empty($orig_event) ? DateTimeFormat::convert($fdt, $tz, 'UTC', 'i') : '00';
 
-               $perms = ACL::getDefaultUserPermissions($orig_event);
-
                if (!$cid && in_array($mode, ['new', 'copy'])) {
-                       $acl = ACL::getFullSelectorHTML($a->user, false, $orig_event);
+                       $acl = ACL::getFullSelectorHTML($a->page, $a->user, false, ACL::getDefaultUserPermissions($orig_event));
                } else {
                        $acl = '';
                }
@@ -506,11 +511,6 @@ function events_content(App $a)
                        '$cid'  => $cid,
                        '$uri'  => $uri,
 
-                       '$allow_cid' => json_encode($perms['allow_cid']),
-                       '$allow_gid' => json_encode($perms['allow_gid']),
-                       '$deny_cid'  => json_encode($perms['deny_cid']),
-                       '$deny_gid'  => json_encode($perms['deny_gid']),
-
                        '$title' => L10n::t('Event details'),
                        '$desc' => L10n::t('Starting date and Title are required.'),
                        '$s_text' => L10n::t('Event Starts:') . ' <span class="required" title="' . L10n::t('Required') . '">*</span>',
index 5fbfa9a5d8e736adaaa6c2ba10a4dc66d4072308..44c7c8b44f9aa4859baf0d606cbee35e7ac1465c 100644 (file)
@@ -377,7 +377,7 @@ function networkFlatView(App $a, $update = 0)
                        (strlen($a->user['allow_cid']) || strlen($a->user['allow_gid']) ||
                        strlen($a->user['deny_cid']) || strlen($a->user['deny_gid'])) ? 'lock' : 'unlock'),
                        'default_perms' => ACL::getDefaultUserPermissions($a->user),
-                       'acl' => ACL::getFullSelectorHTML($a->user, true),
+                       'acl' => ACL::getFullSelectorHTML($a->page, $a->user, true),
                        'bang' => '',
                        'visitor' => 'block',
                        'profile_uid' => local_user(),
@@ -554,7 +554,7 @@ function networkThreadedView(App $a, $update, $parent)
                        (strlen($a->user['allow_cid']) || strlen($a->user['allow_gid']) ||
                        strlen($a->user['deny_cid']) || strlen($a->user['deny_gid']))) ? 'lock' : 'unlock'),
                        'default_perms' => ACL::getDefaultUserPermissions($a->user),
-                       'acl' => ACL::getFullSelectorHTML($a->user, true, $default_permissions),
+                       'acl' => ACL::getFullSelectorHTML($a->page, $a->user, true, $default_permissions),
                        'bang' => (($gid || $cid || $nets) ? '!' : ''),
                        'visitor' => 'block',
                        'profile_uid' => local_user(),
index e0630e7dc9635266efb22d165125770f8a4ca28e..2f3e7d3117cde88b03989d9ac16dde3411ae5429 100644 (file)
@@ -960,7 +960,7 @@ function photos_content(App $a)
 
                $tpl = Renderer::getMarkupTemplate('photos_upload.tpl');
 
-               $aclselect_e = ($visitor ? '' : ACL::getFullSelectorHTML($a->user));
+               $aclselect_e = ($visitor ? '' : ACL::getFullSelectorHTML($a->page, $a->user));
 
                $o .= Renderer::replaceMacros($tpl,[
                        '$pagename' => L10n::t('Upload Photos'),
@@ -1332,7 +1332,7 @@ function photos_content(App $a)
 
                        $album_e = $ph[0]['album'];
                        $caption_e = $ph[0]['desc'];
-                       $aclselect_e = ACL::getFullSelectorHTML($a->user, false, $ph[0]);
+                       $aclselect_e = ACL::getFullSelectorHTML($a->page, $a->user, false, ACL::getDefaultUserPermissions($ph[0]));
 
                        $edit = Renderer::replaceMacros($edit_tpl, [
                                '$id' => $ph[0]['id'],
index 6e32b05426cf9ff0302d8466b409057b670b1970..8b5254976d70fbbe0482d8ae400d532dbcebaac9 100644 (file)
@@ -1206,7 +1206,7 @@ function settings_content(App $a)
                '$permissions' => L10n::t('Default Post Permissions'),
                '$permdesc' => L10n::t("\x28click to open/close\x29"),
                '$visibility' => $profile['net-publish'],
-               '$aclselect' => ACL::getFullSelectorHTML($a->user),
+               '$aclselect' => ACL::getFullSelectorHTML($a->page, $a->user),
                '$suggestme' => $suggestme,
                '$blockwall'=> $blockwall, // array('blockwall', L10n::t('Allow friends to post to your profile page:'), !$blockwall, ''),
                '$blocktags'=> $blocktags, // array('blocktags', L10n::t('Allow friends to tag your posts:'), !$blocktags, ''),
index 7af0bc8995473b452d7aaef051569c66a127b19b..ca98bb6b2392cc118510ee3fad7ec98431e14a8f 100644 (file)
@@ -15,6 +15,7 @@ use Friendica\Core\Renderer;
 use Friendica\Core\Theme;
 use Friendica\Module\Special\HTTPException as ModuleHTTPException;
 use Friendica\Network\HTTPException;
+use Friendica\Util\Strings;
 
 /**
  * Contains the page specific environment variables for the current Page
@@ -29,15 +30,26 @@ class Page implements ArrayAccess
        /**
         * @var array Contains all stylesheets, which should get loaded during page
         */
-       private $stylesheets;
+       private $stylesheets = [];
        /**
         * @var array Contains all scripts, which are added to the footer at last
         */
-       private $footerScripts;
+       private $footerScripts = [];
        /**
         * @var array The page content, which are showed directly
         */
-       private $page;
+       private $page = [
+               'aside'       => '',
+               'bottom'      => '',
+               'content'     => '',
+               'footer'      => '',
+               'htmlhead'    => '',
+               'nav'         => '',
+               'page_title'  => '',
+               'right_aside' => '',
+               'template'    => '',
+               'title'       => '',
+       ];
        /**
         * @var string The basepath of the page
         */
@@ -49,19 +61,6 @@ class Page implements ArrayAccess
        public function __construct(string $basepath)
        {
                $this->basePath = $basepath;
-
-               $this->page = [
-                       'aside'       => '',
-                       'bottom'      => '',
-                       'content'     => '',
-                       'footer'      => '',
-                       'htmlhead'    => '',
-                       'nav'         => '',
-                       'page_title'  => '',
-                       'right_aside' => '',
-                       'template'    => '',
-                       'title'       => ''
-               ];
        }
 
        /**
@@ -224,15 +223,15 @@ class Page implements ArrayAccess
                 * being first
                 */
                $this->page['htmlhead'] = Renderer::replaceMacros($tpl, [
-                               '$local_user'      => local_user(),
-                               '$generator'       => 'Friendica' . ' ' . FRIENDICA_VERSION,
-                               '$delitem'         => $l10n->t('Delete this item?'),
-                               '$update_interval' => $interval,
-                               '$shortcut_icon'   => $shortcut_icon,
-                               '$touch_icon'      => $touch_icon,
-                               '$block_public'    => intval($config->get('system', 'block_public')),
-                               '$stylesheets'     => $this->stylesheets,
-                       ]) . $this->page['htmlhead'];
+                       '$local_user'      => local_user(),
+                       '$generator'       => 'Friendica' . ' ' . FRIENDICA_VERSION,
+                       '$delitem'         => $l10n->t('Delete this item?'),
+                       '$update_interval' => $interval,
+                       '$shortcut_icon'   => $shortcut_icon,
+                       '$touch_icon'      => $touch_icon,
+                       '$block_public'    => intval($config->get('system', 'block_public')),
+                       '$stylesheets'     => array_unique($this->stylesheets),
+               ]) . $this->page['htmlhead'];
        }
 
        /**
@@ -282,8 +281,8 @@ class Page implements ArrayAccess
 
                $tpl                  = Renderer::getMarkupTemplate('footer.tpl');
                $this->page['footer'] = Renderer::replaceMacros($tpl, [
-                               '$footerScripts' => $this->footerScripts,
-                       ]) . $this->page['footer'];
+                       '$footerScripts' => array_unique($this->footerScripts),
+               ]) . $this->page['footer'];
        }
 
        /**
@@ -455,13 +454,13 @@ class Page implements ArrayAccess
                 * to load another page template than the default one.
                 * The page templates are located in /view/php/ or in the theme directory.
                 */
-               if (isset($_GET["mode"])) {
-                       $template = Theme::getPathForFile($_GET["mode"] . '.php');
+               if (isset($_GET['mode'])) {
+                       $template = Theme::getPathForFile('php/' . Strings::sanitizeFilePathItem($_GET['mode']) . '.php');
                }
 
                // If there is no page template use the default page template
                if (empty($template)) {
-                       $template = Theme::getPathForFile("default.php");
+                       $template = Theme::getPathForFile('php/default.php');
                }
 
                // Theme templates expect $a as an App instance
@@ -470,7 +469,6 @@ class Page implements ArrayAccess
                // Used as is in view/php/default.php
                $lang = $l10n->getCurrentLang();
 
-               /// @TODO Looks unsafe (remote-inclusion), is maybe not but Core\Theme::getPathForFile() uses file_exists() but does not escape anything
                require_once $template;
        }
 }
index c2b54821aa8fc8917d145d4228cd297f155bb38b..38719e046cc5ec02a26646b30dcdf77a4a0bc4f3 100644 (file)
@@ -1052,9 +1052,12 @@ class BBCode extends BaseObject
                                $text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ': </p>' . "\n" . $content;
                                break;
                        case 7: // statusnet/GNU Social
-                       case 9: // ActivityPub
                                $text = ($is_quote_share? '<br />' : '') . '<p>' . html_entity_decode('&#x2672; ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '</p>' . "\n";
                                break;
+                       case 9: // ActivityPub
+                               $author = '@<span class="vcard"><a href="' . $author_contact['url'] . '" class="url u-url mention" title="' . $author_contact['addr'] . '"><span class="fn nickname mention">' . $author_contact['addr'] . ':</span></a></span>';
+                               $text = '<div><a href="' . $attributes['link'] . '">' . html_entity_decode('&#x2672;', ENT_QUOTES, 'UTF-8') . '</a> ' . $author . '<blockquote>' . $content . '</blockquote></div>' . "\n";
+                               break;
                        default:
                                // Transforms quoted tweets in rich attachments to avoid nested tweets
                                if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) {
index df2f86e2b7a296288f41fd6814eba8fb146dd6ce..e6dd1a8f32400879a3c03000914334d281c34de5 100644 (file)
@@ -6,13 +6,11 @@
 
 namespace Friendica\Core;
 
+use Friendica\App\Page;
 use Friendica\BaseObject;
-use Friendica\Content\Feature;
 use Friendica\Database\DBA;
 use Friendica\Model\Contact;
-use Friendica\Model\GContact;
-use Friendica\Core\Session;
-use Friendica\Util\Network;
+use Friendica\Model\Group;
 
 /**
  * Handle ACL management and display
@@ -251,36 +249,125 @@ class ACL extends BaseObject
                ];
        }
 
+       /**
+        * Returns the ACL list of contacts for a given user id
+        *
+        * @param int $user_id
+        * @return array
+        * @throws \Exception
+        */
+       public static function getContactListByUserId(int $user_id)
+       {
+               $acl_contacts = Contact::selectToArray(
+                       ['id', 'name', 'addr', 'micro'],
+                       ['uid' => $user_id, 'pending' => false, 'rel' => [Contact::FOLLOWER, Contact::FRIEND]]
+               );
+               array_walk($acl_contacts, function (&$value) {
+                       $value['type'] = 'contact';
+               });
+
+               return $acl_contacts;
+       }
+
+       /**
+        * Returns the ACL list of groups (including meta-groups) for a given user id
+        *
+        * @param int $user_id
+        * @return array
+        */
+       public static function getGroupListByUserId(int $user_id)
+       {
+               $acl_groups = [
+                       [
+                               'id' => Group::FOLLOWERS,
+                               'name' => L10n::t('Followers'),
+                               'addr' => '',
+                               'micro' => 'images/twopeople.png',
+                               'type' => 'group',
+                       ],
+                       [
+                               'id' => Group::MUTUALS,
+                               'name' => L10n::t('Mutuals'),
+                               'addr' => '',
+                               'micro' => 'images/twopeople.png',
+                               'type' => 'group',
+                       ]
+               ];
+               foreach (Group::getByUserId($user_id) as $group) {
+                       $acl_groups[] = [
+                               'id' => $group['id'],
+                               'name' => $group['name'],
+                               'addr' => '',
+                               'micro' => 'images/twopeople.png',
+                               'type' => 'group',
+                       ];
+               }
+
+               return $acl_groups;
+       }
+
        /**
         * Return the full jot ACL selector HTML
         *
+        * @param Page  $page
         * @param array $user                User array
-        * @param bool  $show_jotnets
-        * @param array $default_permissions Static defaults permission array: ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']
+        * @param bool  $for_federation
+        * @param array $default_permissions Static defaults permission array:
+        *                                   [
+        *                                      'allow_cid' => [],
+        *                                      'allow_gid' => [],
+        *                                      'deny_cid' => [],
+        *                                      'deny_gid' => [],
+        *                                      'hidewall' => true/false
+        *                                   ]
         * @return string
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         */
-       public static function getFullSelectorHTML(array $user = null, $show_jotnets = false, array $default_permissions = [])
+       public static function getFullSelectorHTML(Page $page, array $user = null, bool $for_federation = false, array $default_permissions = [])
        {
+               $page->registerFooterScript(Theme::getPathForFile('asset/typeahead.js/dist/typeahead.bundle.js'));
+               $page->registerFooterScript(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.js'));
+               $page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput.css'));
+               $page->registerStylesheet(Theme::getPathForFile('js/friendica-tagsinput/friendica-tagsinput-typeahead.css'));
+
                // Defaults user permissions
                if (empty($default_permissions)) {
                        $default_permissions = self::getDefaultUserPermissions($user);
                }
 
+               $default_permissions = [
+                       'allow_cid' => $default_permissions['allow_cid'] ?? [],
+                       'allow_gid' => $default_permissions['allow_gid'] ?? [],
+                       'deny_cid'  => $default_permissions['deny_cid']  ?? [],
+                       'deny_gid'  => $default_permissions['deny_gid']  ?? [],
+                       'hidewall'  => $default_permissions['hidewall']  ?? false,
+               ];
+
+               if (count($default_permissions['allow_cid'])
+                       + count($default_permissions['allow_gid'])
+                       + count($default_permissions['deny_cid'])
+                       + count($default_permissions['deny_gid'])) {
+                       $visibility = 'custom';
+               } else {
+                       $visibility = 'public';
+                       // Default permission display for custom panel
+                       $default_permissions['allow_gid'] = [Group::FOLLOWERS];
+               }
+
                $jotnets_fields = [];
-               if ($show_jotnets) {
+               if ($for_federation) {
                        $mail_enabled = false;
                        $pubmail_enabled = false;
 
                        if (function_exists('imap_open') && !Config::get('system', 'imap_disabled')) {
-                               $mailacct = DBA::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', local_user()]);
+                               $mailacct = DBA::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', $user['uid']]);
                                if (DBA::isResult($mailacct)) {
                                        $mail_enabled = true;
                                        $pubmail_enabled = !empty($mailacct['pubmail']);
                                }
                        }
 
-                       if (empty($default_permissions['hidewall'])) {
+                       if ($default_permissions['hidewall']) {
                                if ($mail_enabled) {
                                        $jotnets_fields[] = [
                                                'type' => 'checkbox',
@@ -296,27 +383,35 @@ class ACL extends BaseObject
                        }
                }
 
+               $acl_contacts = self::getContactListByUserId($user['uid']);
+
+               $acl_groups = self::getGroupListByUserId($user['uid']);
+
+               $acl_list = array_merge($acl_groups, $acl_contacts);
+
                $tpl = Renderer::getMarkupTemplate('acl_selector.tpl');
                $o = Renderer::replaceMacros($tpl, [
-                       '$showall' => L10n::t('Visible to everybody'),
-                       '$show' => L10n::t('show'),
-                       '$hide' => L10n::t('don\'t show'),
-                       '$allowcid' => json_encode(($default_permissions['allow_cid'] ?? '') ?: []), // We need arrays for
-                       '$allowgid' => json_encode(($default_permissions['allow_gid'] ?? '') ?: []), // Javascript since we
-                       '$denycid'  => json_encode(($default_permissions['deny_cid']  ?? '') ?: []), // call .remove() and
-                       '$denygid'  => json_encode(($default_permissions['deny_gid']  ?? '') ?: []), // .push() on these values
-                       '$networks' => $show_jotnets,
-                       '$emailcc' => L10n::t('CC: email addresses'),
-                       '$emtitle' => L10n::t('Example: bob@example.com, mary@example.com'),
-                       '$jotnets_enabled' => empty($default_permissions['hidewall']),
+                       '$public_title'   => L10n::t('Public'),
+                       '$public_desc'    => L10n::t('This content will be shown to all your followers and can be seen in the community pages and by anyone with its link.'),
+                       '$custom_title'   => L10n::t('Limited/Private'),
+                       '$custom_desc'    => L10n::t('This content will be shown only to the people in the first box, to the exception of the people mentioned in the second box. It won\'t appear anywhere public.'),
+                       '$allow_label'    => L10n::t('Show to:'),
+                       '$deny_label'     => L10n::t('Except to:'),
+                       '$emailcc'        => L10n::t('CC: email addresses'),
+                       '$emtitle'        => L10n::t('Example: bob@example.com, mary@example.com'),
                        '$jotnets_summary' => L10n::t('Connectors'),
-                       '$jotnets_fields' => $jotnets_fields,
                        '$jotnets_disabled_label' => L10n::t('Connectors disabled, since "%s" is enabled.', L10n::t('Hide your profile details from unknown viewers?')),
-                       '$aclModalTitle' => L10n::t('Permissions'),
-                       '$aclModalDismiss' => L10n::t('Close'),
-                       '$features' => [
-                               'aclautomention' => !empty($user['uid']) && Feature::isEnabled($user['uid'], 'aclautomention') ? 'true' : 'false'
-                       ],
+                       '$visibility'     => $visibility,
+                       '$acl_contacts'   => $acl_contacts,
+                       '$acl_groups'     => $acl_groups,
+                       '$acl_list'       => $acl_list,
+                       '$contact_allow'  => implode(',', $default_permissions['allow_cid']),
+                       '$group_allow'    => implode(',', $default_permissions['allow_gid']),
+                       '$contact_deny'   => implode(',', $default_permissions['deny_cid']),
+                       '$group_deny'     => implode(',', $default_permissions['deny_gid']),
+                       '$for_federation' => $for_federation,
+                       '$jotnets_fields' => $jotnets_fields,
+                       '$user_hidewall'  => $default_permissions['hidewall'],
                ]);
 
                return $o;
index 0888f390a694c8d59769a80e5a876e01ce9e8e37..f367d28587a9452b265f41dc9a080e146de7e2a7 100644 (file)
@@ -149,7 +149,7 @@ class System extends BaseObject
         * and adds an application/json HTTP header to the output.
         * After finishing the process is getting killed.
         *
-        * @param array  $x The input content.
+        * @param mixed  $x The input content.
         * @param string $content_type Type of the input (Default: 'application/json').
         */
        public static function jsonExit($x, $content_type = 'application/json') {
index 61798a3969d99e7345dc2f0559c9018db488bc96..4f870687ce0d08e577a3459589ce07ac139576da 100644 (file)
@@ -31,12 +31,12 @@ class Theme
                        }
                }
 
-               return $allowed_themes;
+               return array_unique($allowed_themes);
        }
 
        public static function setAllowedList(array $allowed_themes)
        {
-               Config::set('system', 'allowed_themes', implode(',', $allowed_themes));
+               Config::set('system', 'allowed_themes', implode(',', array_unique($allowed_themes)));
        }
 
        /**
@@ -185,45 +185,33 @@ class Theme
        /**
         * @brief Get the full path to relevant theme files by filename
         *
-        * This function search in the theme directory (and if not present in global theme directory)
-        * if there is a directory with the file extension and  for a file with the given
-        * filename.
+        * This function searches in order in the current theme directory, in the current theme parent directory, and lastly
+        * in the base view/ folder.
         *
         * @param string $file Filename
-        * @param string $root Full root path
         * @return string Path to the file or empty string if the file isn't found
-        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        * @throws \Exception
         */
-       public static function getPathForFile($file, $root = '')
+       public static function getPathForFile($file)
        {
-               $file = basename($file);
+               $a = BaseObject::getApp();
+
+               $theme = $a->getCurrentTheme();
+
+               $parent = Strings::sanitizeFilePathItem($a->theme_info['extends'] ?? $theme);
 
-               // Make sure $root ends with a slash / if it's not blank
-               if ($root !== '' && $root[strlen($root) - 1] !== '/') {
-                       $root = $root . '/';
-               }
-               $theme_info = \get_app()->theme_info;
-               if (is_array($theme_info) && array_key_exists('extends', $theme_info)) {
-                       $parent = $theme_info['extends'];
-               } else {
-                       $parent = 'NOPATH';
-               }
-               $theme = \get_app()->getCurrentTheme();
-               $parent = Strings::sanitizeFilePathItem($parent);
-               $ext = substr($file, strrpos($file, '.') + 1);
                $paths = [
-                       "{$root}view/theme/$theme/$ext/$file",
-                       "{$root}view/theme/$parent/$ext/$file",
-                       "{$root}view/$ext/$file",
+                       "view/theme/$theme/$file",
+                       "view/theme/$parent/$file",
+                       "view/$file",
                ];
-               foreach ($paths as $p) {
-                       // strpos() is faster than strstr when checking if one string is in another (http://php.net/manual/en/function.strstr.php)
-                       if (strpos($p, 'NOPATH') !== false) {
-                               continue;
-                       } elseif (file_exists($p)) {
-                               return $p;
+
+               foreach ($paths as $path) {
+                       if (file_exists($path)) {
+                               return $path;
                        }
                }
+
                return '';
        }
 
index 64b868466a589d4c3203935db09bf64fbd8211fa..3be2a80e560c098a1cdff5be82dca55ad4d020f5 100644 (file)
@@ -328,13 +328,28 @@ class Group extends BaseObject
                }
 
                $return = [];
+               $pubmail = false;
+               $networks = Protocol::SUPPORT_PRIVATE;
+
+               $mailacct = DBA::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', $uid]);
+               if (DBA::isResult($mailacct)) {
+                       $pubmail = $mailacct['pubmail'];
+               }
+
+               if (!$pubmail) {
+                       $networks = array_diff($networks, [Protocol::MAIL]);
+               }
 
                $key = array_search(self::FOLLOWERS, $group_ids);
                if ($key !== false) {
                        $followers = Contact::selectToArray(['id'], [
                                'uid' => $uid,
                                'rel' => [Contact::FOLLOWER, Contact::FRIEND],
-                               'network' => Protocol::SUPPORT_PRIVATE,
+                               'network' => $networks,
+                               'contact-type' => [Contact::TYPE_UNKNOWN, Contact::TYPE_PERSON],
+                               'archive' => false,
+                               'pending' => false,
+                               'blocked' => false,
                        ]);
 
                        foreach ($followers as $follower) {
@@ -349,7 +364,11 @@ class Group extends BaseObject
                        $mutuals = Contact::selectToArray(['id'], [
                                'uid' => $uid,
                                'rel' => [Contact::FRIEND],
-                               'network' => Protocol::SUPPORT_PRIVATE,
+                               'network' => $networks,
+                               'contact-type' => [Contact::TYPE_UNKNOWN, Contact::TYPE_PERSON],
+                               'archive' => false,
+                               'pending' => false,
+                               'blocked' => false,
                        ]);
 
                        foreach ($mutuals as $mutual) {
index a50f23c256963e160fb4d501b778cad28fee3e47..08bac2c1d06bba6add18bc35c669e7b58a6dd4e1 100644 (file)
@@ -44,7 +44,7 @@ class Bookmarklet extends BaseModule
                                'nickname'         => $app->user['nickname'],
                                'lockstate'        => ((is_array($app->user) && ((strlen($app->user['allow_cid'])) || (strlen($app->user['allow_gid'])) || (strlen($app->user['deny_cid'])) || (strlen($app->user['deny_gid'])))) ? 'lock' : 'unlock'),
                                'default_perms'    => ACL::getDefaultUserPermissions($app->user),
-                               'acl'              => ACL::getFullSelectorHTML($app->user, true),
+                               'acl'              => ACL::getFullSelectorHTML($app->page, $app->user, true),
                                'bang'             => '',
                                'visitor'          => 'block',
                                'profile_uid'      => local_user(),
index ded5ffbe2343ec2e15161e1425b9263aca27241a..5ef06b72a183b22488820bf6dc8c74b3823ff983 100644 (file)
@@ -926,7 +926,7 @@ class Contact extends BaseModule
                                        'default_location' => $a->user['default-location'],
                                        'nickname' => $a->user['nickname'],
                                        'lockstate' => (is_array($a->user) && (strlen($a->user['allow_cid']) || strlen($a->user['allow_gid']) || strlen($a->user['deny_cid']) || strlen($a->user['deny_gid'])) ? 'lock' : 'unlock'),
-                                       'acl' => ACL::getFullSelectorHTML($a->user, true),
+                                       'acl' => ACL::getFullSelectorHTML($a->page, $a->user, true),
                                        'bang' => '',
                                        'visitor' => 'block',
                                        'profile_uid' => local_user(),
index ad0a2d805cc6fd70199b949f87f575cd9edb8be2..db44ee3d14449975abda86df5e3346d05f64b238 100644 (file)
@@ -4,10 +4,13 @@ namespace Friendica\Module\Item;
 
 use Friendica\BaseModule;
 use Friendica\Content\Feature;
+use Friendica\Core\ACL;
 use Friendica\Core\Config;
 use Friendica\Core\Hook;
 use Friendica\Core\L10n;
 use Friendica\Core\Renderer;
+use Friendica\Core\System;
+use Friendica\Core\Theme;
 use Friendica\Database\DBA;
 use Friendica\Model\Contact;
 use Friendica\Model\FileTag;
@@ -45,7 +48,7 @@ class Compose extends BaseModule
                }
 
                /// @TODO Retrieve parameter from router
-               $posttype = $a->argv[1] ?? Item::PT_ARTICLE;
+               $posttype = $parameters['type'] ?? Item::PT_ARTICLE;
                if (!in_array($posttype, [Item::PT_ARTICLE, Item::PT_PERSONAL_NOTE])) {
                        switch ($posttype) {
                                case 'note':
@@ -62,20 +65,37 @@ class Compose extends BaseModule
                /** @var ACLFormatter $aclFormatter */
                $aclFormatter = self::getClass(ACLFormatter::class);
 
+               $contact_allow_list = $aclFormatter->expand($user['allow_cid']);
+               $group_allow_list   = $aclFormatter->expand($user['allow_gid']);
+               $contact_deny_list  = $aclFormatter->expand($user['deny_cid']);
+               $group_deny_list    = $aclFormatter->expand($user['deny_gid']);
+
                switch ($posttype) {
                        case Item::PT_PERSONAL_NOTE:
                                $compose_title = L10n::t('Compose new personal note');
                                $type = 'note';
                                $doesFederate = false;
-                               $contact_allow = $a->contact['id'];
-                               $group_allow = '';
+                               $contact_allow_list = [$a->contact['id']];
+                               $group_allow_list = [];
+                               $contact_deny_list = [];
+                               $group_deny_list = [];
                                break;
                        default:
                                $compose_title = L10n::t('Compose new post');
                                $type = 'post';
                                $doesFederate = true;
-                               $contact_allow = implode(',', $aclFormatter->expand($user['allow_cid']));
-                               $group_allow = implode(',', $aclFormatter->expand($user['allow_gid'])) ?: Group::FOLLOWERS;
+
+                               if ($_REQUEST['contact_allow']
+                                       . $_REQUEST['group_allow']
+                                       . $_REQUEST['contact_deny']
+                                   . $_REQUEST['group_deny'])
+                               {
+                                       $contact_allow_list = $_REQUEST['contact_allow'] ? explode(',', $_REQUEST['contact_allow']) : [];
+                                       $group_allow_list   = $_REQUEST['group_allow']   ? explode(',', $_REQUEST['group_allow'])   : [];
+                                       $contact_deny_list  = $_REQUEST['contact_deny']  ? explode(',', $_REQUEST['contact_deny'])  : [];
+                                       $group_deny_list    = $_REQUEST['group_deny']    ? explode(',', $_REQUEST['group_deny'])    : [];
+                               }
+
                                break;
                }
 
@@ -84,93 +104,19 @@ class Compose extends BaseModule
                $body          = $_REQUEST['body']          ?? '';
                $location      = $_REQUEST['location']      ?? $user['default-location'];
                $wall          = $_REQUEST['wall']          ?? $type == 'post';
-               $contact_allow = $_REQUEST['contact_allow'] ?? $contact_allow;
-               $group_allow   = $_REQUEST['group_allow']   ?? $group_allow;
-               $contact_deny  = $_REQUEST['contact_deny']  ?? implode(',', $aclFormatter->expand($user['deny_cid']));
-               $group_deny    = $_REQUEST['group_deny']    ?? implode(',', $aclFormatter->expand($user['deny_gid']));
-               $visibility    = ($contact_allow . $user['allow_gid'] . $user['deny_cid'] . $user['deny_gid']) ? 'custom' : 'public';
-
-               $acl_contacts = Contact::selectToArray(['id', 'name', 'addr', 'micro'], ['uid' => local_user(), 'pending' => false, 'rel' => [Contact::FOLLOWER, Contact::FRIEND]]);
-               array_walk($acl_contacts, function (&$value) {
-                       $value['type'] = 'contact';
-               });
-
-               $acl_groups = [
-                       [
-                               'id' => Group::FOLLOWERS,
-                               'name' => L10n::t('Followers'),
-                               'addr' => '',
-                               'micro' => 'images/twopeople.png',
-                               'type' => 'group',
-                       ],
-                       [
-                               'id' => Group::MUTUALS,
-                               'name' => L10n::t('Mutuals'),
-                               'addr' => '',
-                               'micro' => 'images/twopeople.png',
-                               'type' => 'group',
-                       ]
-               ];
-               foreach (Group::getByUserId(local_user()) as $group) {
-                       $acl_groups[] = [
-                               'id' => $group['id'],
-                               'name' => $group['name'],
-                               'addr' => '',
-                               'micro' => 'images/twopeople.png',
-                               'type' => 'group',
-                       ];
-               }
-
-               $acl = array_merge($acl_groups, $acl_contacts);
-
-               $jotnets_fields = [];
-               $mail_enabled = false;
-               $pubmail_enabled = false;
-               if (function_exists('imap_open') && !Config::get('system', 'imap_disabled')) {
-                       $mailacct = DBA::selectFirst('mailacct', ['pubmail'], ['`uid` = ? AND `server` != ""', local_user()]);
-                       if (DBA::isResult($mailacct)) {
-                               $mail_enabled = true;
-                               $pubmail_enabled = !empty($mailacct['pubmail']);
-                       }
-               }
-
-               if (empty($user['hidewall'])) {
-                       if ($mail_enabled) {
-                               $jotnets_fields[] = [
-                                       'type' => 'checkbox',
-                                       'field' => [
-                                               'pubmail_enable',
-                                               L10n::t('Post to Email'),
-                                               $pubmail_enabled
-                                       ]
-                               ];
-                       }
-
-                       Hook::callAll('jot_networks', $jotnets_fields);
-               }
 
                $jotplugins = '';
                Hook::callAll('jot_tool', $jotplugins);
 
                // Output
-
-               $a->registerFooterScript('view/js/ajaxupload.js');
-               $a->registerFooterScript('view/js/linkPreview.js');
-               $a->registerFooterScript('view/asset/typeahead.js/dist/typeahead.bundle.js');
-               $a->registerFooterScript('view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.js');
-               $a->registerStylesheet('view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.css');
-               $a->registerStylesheet('view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput-typeahead.css');
-
-               $tpl = Renderer::getMarkupTemplate('item/compose-footer.tpl');
-               $a->page['footer'] .= Renderer::replaceMacros($tpl, [
-                       '$acl_contacts' => $acl_contacts,
-                       '$acl_groups' => $acl_groups,
-                       '$acl' => $acl,
-               ]);
+               $a->page->registerFooterScript(Theme::getPathForFile('js/ajaxupload.js'));
+               $a->page->registerFooterScript(Theme::getPathForFile('js/linkPreview.js'));
+               $a->page->registerFooterScript(Theme::getPathForFile('js/compose.js'));
 
                $tpl = Renderer::getMarkupTemplate('item/compose.tpl');
                return Renderer::replaceMacros($tpl, [
                        '$compose_title'=> $compose_title,
+                       '$visibility_title'=> L10n::t('Visibility'),
                        '$id'           => 0,
                        '$posttype'     => $posttype,
                        '$type'         => $type,
@@ -197,25 +143,26 @@ class Compose extends BaseModule
                        '$wait'         => L10n::t('Please wait'),
                        '$placeholdertitle' => L10n::t('Set title'),
                        '$placeholdercategory' => (Feature::isEnabled(local_user(),'categories') ? L10n::t('Categories (comma-separated list)') : ''),
-                       '$public_title'  => L10n::t('Public'),
-                       '$public_desc'  => L10n::t('This post will be sent to all your followers and can be seen in the community pages and by anyone with its link.'),
-                       '$custom_title' => L10n::t('Limited/Private'),
-                       '$custom_desc'  => L10n::t('This post will be sent only to the people in the first box, to the exception of the people mentioned in the second box. It won\'t appear anywhere public.'),
-                       '$emailcc'      => L10n::t('CC: email addresses'),
+
                        '$title'        => $title,
                        '$category'     => $category,
                        '$body'         => $body,
                        '$location'     => $location,
-                       '$visibility'   => $visibility,
-                       '$contact_allow'=> $contact_allow,
-                       '$group_allow'  => $group_allow,
-                       '$contact_deny' => $contact_deny,
-                       '$group_deny'   => $group_deny,
+
+                       '$contact_allow'=> implode(',', $contact_allow_list),
+                       '$group_allow'  => implode(',', $group_allow_list),
+                       '$contact_deny' => implode(',', $contact_deny_list),
+                       '$group_deny'   => implode(',', $group_deny_list),
+
                        '$jotplugins'   => $jotplugins,
-                       '$doesFederate' => $doesFederate,
-                       '$jotnets_fields'=> $jotnets_fields,
                        '$sourceapp'    => L10n::t($a->sourcename),
-                       '$rand_num'     => Crypto::randomDigits(12)
+                       '$rand_num'     => Crypto::randomDigits(12),
+                       '$acl_selector'  => ACL::getFullSelectorHTML($a->page, $a->user, $doesFederate, [
+                               'allow_cid' => $contact_allow_list,
+                               'allow_gid' => $group_allow_list,
+                               'deny_cid'  => $contact_deny_list,
+                               'deny_gid'  => $group_deny_list,
+                       ]),
                ]);
        }
 }
index 4590bc8c84c80e3cadc8e2a2962fe7462ce7837f..e67f2113cdaa8a152db2efd91211fb499cd0b548 100644 (file)
@@ -73,6 +73,6 @@ class Ignore extends BaseModule
                }
 
                // the json doesn't really matter, it will either be 0 or 1
-               System::jsonExit([$ignored]);
+               System::jsonExit($ignored);
        }
 }
index 28f23196f9a44417f5aed95b5f51d66d0ec5b169..deec94d93ffba7f787156625ea44acb61ce833e9 100644 (file)
@@ -13,84 +13,131 @@ use Friendica\Core\System;
  */
 class NodeInfo extends BaseModule
 {
-       public static function init(array $parameters = [])
+       public static function rawContent(array $parameters = [])
        {
-               $config = self::getApp()->getConfig();
+               $app = self::getApp();
 
-               if (!$config->get('system', 'nodeinfo')) {
+               if ($parameters['version'] == '1.0') {
+                       self::printNodeInfo1($app);
+               } elseif ($parameters['version'] == '2.0') {
+                       self::printNodeInfo2($app);
+               } else {
                        throw new \Friendica\Network\HTTPException\NotFoundException();
                }
        }
 
-       public static function rawContent(array $parameters = [])
+       /**
+        * Return the supported services
+        *
+        * @param App $app
+        *
+        * @return array with supported services
+       */
+       private static function getUsage(App $app)
        {
-               $app = self::getApp();
+               $config = $app->getConfig();
 
-               // @TODO: Replace with parameter from router
-               // if the first argument is ".well-known", print the well-known text
-               if (($app->argc > 1) && ($app->argv[0] == '.well-known')) {
-                       self::printWellKnown($app);
-               // otherwise print the nodeinfo
-               } else {
-                       self::printNodeInfo($app);
+               $usage = [];
+
+               if (!empty($config->get('system', 'nodeinfo'))) {
+                       $usage['users'] = [
+                               'total'          => intval($config->get('nodeinfo', 'total_users')),
+                               'activeHalfyear' => intval($config->get('nodeinfo', 'active_users_halfyear')),
+                               'activeMonth'    => intval($config->get('nodeinfo', 'active_users_monthly'))
+                       ];
+                       $usage['localPosts'] = intval($config->get('nodeinfo', 'local_posts'));
+                       $usage['localComments'] = intval($config->get('nodeinfo', 'local_comments'));
                }
+
+               return $usage;
        }
 
        /**
-        * Prints the well-known nodeinfo redirect
+        * Return the supported services
         *
         * @param App $app
         *
-        * @throws \Friendica\Network\HTTPException\NotFoundException
-        */
-       private static function printWellKnown(App $app)
+        * @return array with supported services
+       */
+       private static function getServices(App $app)
        {
-               $config = $app->getConfig();
+               $services = [
+                       'inbound'  => [],
+                       'outbound' => [],
+               ];
 
-               if (!$config->get('system', 'nodeinfo')) {
-                       throw new \Friendica\Network\HTTPException\NotFoundException();
+               if (Addon::isEnabled('blogger')) {
+                       $services['outbound'][] = 'blogger';
+               }
+               if (Addon::isEnabled('dwpost')) {
+                       $services['outbound'][] = 'dreamwidth';
+               }
+               if (Addon::isEnabled('statusnet')) {
+                       $services['inbound'][] = 'gnusocial';
+                       $services['outbound'][] = 'gnusocial';
+               }
+               if (Addon::isEnabled('ijpost')) {
+                       $services['outbound'][] = 'insanejournal';
+               }
+               if (Addon::isEnabled('libertree')) {
+                       $services['outbound'][] = 'libertree';
+               }
+               if (Addon::isEnabled('buffer')) {
+                       $services['outbound'][] = 'linkedin';
+               }
+               if (Addon::isEnabled('ljpost')) {
+                       $services['outbound'][] = 'livejournal';
+               }
+               if (Addon::isEnabled('buffer')) {
+                       $services['outbound'][] = 'pinterest';
+               }
+               if (Addon::isEnabled('posterous')) {
+                       $services['outbound'][] = 'posterous';
+               }
+               if (Addon::isEnabled('pumpio')) {
+                       $services['inbound'][] = 'pumpio';
+                       $services['outbound'][] = 'pumpio';
                }
 
-               $nodeinfo = [
-                       'links' => [[
-                               'rel'  => 'http://nodeinfo.diaspora.software/ns/schema/1.0',
-                               'href' => $app->getBaseURL() . '/nodeinfo/1.0']]
-               ];
+               $services['outbound'][] = 'smtp';
 
-               header('Content-type: application/json; charset=utf-8');
-               echo json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
-               exit;
+               if (Addon::isEnabled('tumblr')) {
+                       $services['outbound'][] = 'tumblr';
+               }
+               if (Addon::isEnabled('twitter') || Addon::isEnabled('buffer')) {
+                       $services['outbound'][] = 'twitter';
+               }
+               if (Addon::isEnabled('wppost')) {
+                       $services['outbound'][] = 'wordpress';
+               }
+
+               return $services;
        }
 
        /**
-        * Print the nodeinfo
+        * Print the nodeinfo version 1
         *
         * @param App $app
         */
-       private static function printNodeInfo(App $app)
+       private static function printNodeInfo1(App $app)
        {
                $config = $app->getConfig();
 
-               $smtp = (function_exists('imap_open') && !$config->get('system', 'imap_disabled') && !$config->get('system', 'dfrn_only'));
-
                $nodeinfo = [
-                       'version'           => 1.0,
+                       'version'           => '1.0',
                        'software'          => [
                                'name'    => 'friendica',
                                'version' => FRIENDICA_VERSION . '-' . DB_UPDATE_VERSION,
                        ],
                        'protocols'         => [
                                'inbound'  => [
-                                       'friendica',
+                                       'friendica', 'activitypub'
                                ],
                                'outbound' => [
-                                       'friendica',
+                                       'friendica', 'activitypub'
                                ],
                        ],
-                       'services'          => [
-                               'inbound'  => [],
-                               'outbound' => [],
-                       ],
+                       'services'          => [],
                        'usage'             => [],
                        'openRegistrations' => intval($config->get('config', 'register_policy')) !== Register::CLOSED,
                        'metadata'          => [
@@ -108,75 +155,80 @@ class NodeInfo extends BaseModule
                        $nodeinfo['protocols']['outbound'][] = 'gnusocial';
                }
 
-               if (!empty($config->get('system', 'nodeinfo'))) {
+               $nodeinfo['usage'] = self::getUsage($app);
 
-                       $nodeinfo['usage']['users'] = [
-                               'total'          => intval($config->get('nodeinfo', 'total_users')),
-                               'activeHalfyear' => intval($config->get('nodeinfo', 'active_users_halfyear')),
-                               'activeMonth'    => intval($config->get('nodeinfo', 'active_users_monthly'))
-                       ];
-                       $nodeinfo['usage']['localPosts'] = intval($config->get('nodeinfo', 'local_posts'));
-                       $nodeinfo['usage']['localComments'] = intval($config->get('nodeinfo', 'local_comments'));
-
-                       if (Addon::isEnabled('blogger')) {
-                               $nodeinfo['services']['outbound'][] = 'blogger';
-                       }
-                       if (Addon::isEnabled('dwpost')) {
-                               $nodeinfo['services']['outbound'][] = 'dreamwidth';
-                       }
-                       if (Addon::isEnabled('statusnet')) {
-                               $nodeinfo['services']['inbound'][] = 'gnusocial';
-                               $nodeinfo['services']['outbound'][] = 'gnusocial';
-                       }
-                       if (Addon::isEnabled('ijpost')) {
-                               $nodeinfo['services']['outbound'][] = 'insanejournal';
-                       }
-                       if (Addon::isEnabled('libertree')) {
-                               $nodeinfo['services']['outbound'][] = 'libertree';
-                       }
-                       if (Addon::isEnabled('buffer')) {
-                               $nodeinfo['services']['outbound'][] = 'linkedin';
-                       }
-                       if (Addon::isEnabled('ljpost')) {
-                               $nodeinfo['services']['outbound'][] = 'livejournal';
-                       }
-                       if (Addon::isEnabled('buffer')) {
-                               $nodeinfo['services']['outbound'][] = 'pinterest';
-                       }
-                       if (Addon::isEnabled('posterous')) {
-                               $nodeinfo['services']['outbound'][] = 'posterous';
-                       }
-                       if (Addon::isEnabled('pumpio')) {
-                               $nodeinfo['services']['inbound'][] = 'pumpio';
-                               $nodeinfo['services']['outbound'][] = 'pumpio';
-                       }
-
-                       if ($smtp) {
-                               $nodeinfo['services']['outbound'][] = 'smtp';
-                       }
-                       if (Addon::isEnabled('tumblr')) {
-                               $nodeinfo['services']['outbound'][] = 'tumblr';
-                       }
-                       if (Addon::isEnabled('twitter') || Addon::isEnabled('buffer')) {
-                               $nodeinfo['services']['outbound'][] = 'twitter';
-                       }
-                       if (Addon::isEnabled('wppost')) {
-                               $nodeinfo['services']['outbound'][] = 'wordpress';
-                       }
-                       $nodeinfo['metadata']['protocols'] = $nodeinfo['protocols'];
-                       $nodeinfo['metadata']['protocols']['outbound'][] = 'atom1.0';
-                       $nodeinfo['metadata']['protocols']['inbound'][] = 'atom1.0';
-                       $nodeinfo['metadata']['protocols']['inbound'][] = 'rss2.0';
-
-                       $nodeinfo['metadata']['services'] = $nodeinfo['services'];
-
-                       if (Addon::isEnabled('twitter')) {
-                               $nodeinfo['metadata']['services']['inbound'][] = 'twitter';
-                       }
-
-                       $nodeinfo['metadata']['explicitContent'] = $config->get('system', 'explicit_content', false) == true;
+               $nodeinfo['services'] = self::getServices($app);
+
+               $nodeinfo['metadata']['protocols'] = $nodeinfo['protocols'];
+               $nodeinfo['metadata']['protocols']['outbound'][] = 'atom1.0';
+               $nodeinfo['metadata']['protocols']['inbound'][] = 'atom1.0';
+               $nodeinfo['metadata']['protocols']['inbound'][] = 'rss2.0';
+
+               $nodeinfo['metadata']['services'] = $nodeinfo['services'];
+
+               if (Addon::isEnabled('twitter')) {
+                       $nodeinfo['metadata']['services']['inbound'][] = 'twitter';
                }
 
+               $nodeinfo['metadata']['explicitContent'] = $config->get('system', 'explicit_content', false) == true;
+
+               header('Content-type: application/json; charset=utf-8');
+               echo json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+               exit;
+       }
+
+       /**
+        * Print the nodeinfo version 2
+        *
+        * @param App $app
+        */
+       private static function printNodeInfo2(App $app)
+       {
+               $config = $app->getConfig();
+
+               $imap = (function_exists('imap_open') && !$config->get('system', 'imap_disabled') && !$config->get('system', 'dfrn_only'));
+
+               $nodeinfo = [
+                       'version'           => '2.0',
+                       'software'          => [
+                               'name'    => 'friendica',
+                               'version' => FRIENDICA_VERSION . '-' . DB_UPDATE_VERSION,
+                       ],
+                       'protocols'         => ['dfrn', 'activitypub'],
+                       'services'          => [],
+                       'usage'             => [],
+                       'openRegistrations' => intval($config->get('config', 'register_policy')) !== Register::CLOSED,
+                       'metadata'          => [
+                               'nodeName' => $config->get('config', 'sitename'),
+                       ],
+               ];
+
+               if (!empty($config->get('system', 'diaspora_enabled'))) {
+                       $nodeinfo['protocols'][] = 'diaspora';
+               }
+
+               if (empty($config->get('system', 'ostatus_disabled'))) {
+                       $nodeinfo['protocols'][] = 'ostatus';
+               }
+
+               $nodeinfo['usage'] = self::getUsage($app);
+
+               $nodeinfo['services'] = self::getServices($app);
+
+               if (Addon::isEnabled('twitter')) {
+                       $nodeinfo['services']['inbound'][] = 'twitter';
+               }
+
+               $nodeinfo['services']['inbound'][]  = 'atom1.0';
+               $nodeinfo['services']['inbound'][]  = 'rss2.0';
+               $nodeinfo['services']['outbound'][] = 'atom1.0';
+
+               if ($imap) {
+                       $nodeinfo['services']['inbound'][] = 'imap';
+               }
+
+               $nodeinfo['metadata']['explicitContent'] = $config->get('system', 'explicit_content', false) == true;
+
                header('Content-type: application/json; charset=utf-8');
                echo json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
                exit;
index 5538be18889910c035ec0c83275ef69d6e3b7035..df576369265f6091048bc8b2e3b8ea87d17aca58 100644 (file)
@@ -42,7 +42,14 @@ class Objects extends BaseModule
                        }
                }
 
-               $data = ActivityPub\Transmitter::createObjectFromItemID($item['id']);
+               $activity = ActivityPub\Transmitter::createActivityFromItem($item['id'], true);
+               // Only display "Create" activity objects here, no reshares or anything else
+               if (!is_array($activity['object']) || ($activity['type'] != 'Create')) {
+                       throw new \Friendica\Network\HTTPException\NotFoundException();
+               }
+
+               $data = ['@context' => ActivityPub::CONTEXT];
+               $data = array_merge($data, $activity['object']);
 
                header('Content-Type: application/activity+json');
                echo json_encode($data);
index aab5918567fbab92582531c7967e1ced93bc32d1..db1a6f86b3db44e4674aeb8394772f12d6373df0 100644 (file)
@@ -208,7 +208,7 @@ class Profile extends BaseModule
                                                || strlen($a->user['deny_cid'])
                                                || strlen($a->user['deny_gid'])
                                        ) ? 'lock' : 'unlock',
-                                       'acl' => $is_owner ? ACL::getFullSelectorHTML($a->user, true) : '',
+                                       'acl' => $is_owner ? ACL::getFullSelectorHTML($a->page, $a->user, true) : '',
                                        'bang' => '',
                                        'visitor' => $is_owner || $commvisitor ? 'block' : 'none',
                                        'profile_uid' => $a->profile['profile_uid'],
diff --git a/src/Module/WellKnown/NodeInfo.php b/src/Module/WellKnown/NodeInfo.php
new file mode 100644 (file)
index 0000000..7d87252
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+namespace Friendica\Module\WellKnown;
+
+use Friendica\App;
+use Friendica\BaseModule;
+
+/**
+ * Standardized way of exposing metadata about a server running one of the distributed social networks.
+ * @see https://github.com/jhass/nodeinfo/blob/master/PROTOCOL.md
+ */
+class NodeInfo extends BaseModule
+{
+       public static function rawContent(array $parameters = [])
+       {
+               $app = self::getApp();
+
+               self::printWellKnown($app);
+       }
+
+       /**
+        * Prints the well-known nodeinfo redirect
+        *
+        * @param App $app
+        *
+        * @throws \Friendica\Network\HTTPException\NotFoundException
+        */
+       private static function printWellKnown(App $app)
+       {
+               $nodeinfo = [
+                       'links' => [
+                               ['rel'  => 'http://nodeinfo.diaspora.software/ns/schema/1.0',
+                               'href' => $app->getBaseURL() . '/nodeinfo/1.0'],
+                               ['rel'  => 'http://nodeinfo.diaspora.software/ns/schema/2.0',
+                               'href' => $app->getBaseURL() . '/nodeinfo/2.0'],
+                       ]
+               ];
+
+               header('Content-type: application/json; charset=utf-8');
+               echo json_encode($nodeinfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+               exit;
+       }
+}
index 981bf76c7d6f576423265d9d4ac358f7da542065..2c4e841acbdd5592e58e72c416e63381d14f0a4f 100644 (file)
@@ -378,6 +378,12 @@ class Post extends BaseObject
 
                $tags = Term::populateTagsFromItem($item);
 
+               $ago = Temporal::getRelativeDate($item['created']);
+               $ago_received = Temporal::getRelativeDate($item['received']);
+               if (Config::get('system', 'show_received') && (abs(strtotime($item['created']) - strtotime($item['received'])) > Config::get('system', 'show_received_seconds')) && ($ago != $ago_received)) {
+                       $ago = L10n::t('%s (Received %s)', $ago, $ago_received);
+               }
+
                $tmp_item = [
                        'template'        => $this->getTemplate(),
                        'type'            => implode("", array_slice(explode("/", $item['verb']), -1)),
@@ -412,7 +418,7 @@ class Post extends BaseObject
                        'sparkle'         => $sparkle,
                        'title'           => $title_e,
                        'localtime'       => DateTimeFormat::local($item['created'], 'r'),
-                       'ago'             => $item['app'] ? L10n::t('%s from %s', Temporal::getRelativeDate($item['created']), $item['app']) : Temporal::getRelativeDate($item['created']),
+                       'ago'             => $item['app'] ? L10n::t('%s from %s', $ago, $item['app']) : $ago,
                        'app'             => $item['app'],
                        'created'         => Temporal::getRelativeDate($item['created']),
                        'lock'            => $lock,
index fa8e4bf46fc71996433e73e56d781e407cd9571d..a9f5ed20a1976bab6ae936c52d6da951c2023603 100644 (file)
@@ -176,9 +176,11 @@ class Transmitter
 
                        $items = Item::select(['id'], $condition, ['limit' => [($page - 1) * 20, 20], 'order' => ['created' => true]]);
                        while ($item = Item::fetch($items)) {
-                               $object = self::createObjectFromItemID($item['id']);
-                               unset($object['@context']);
-                               $list[] = $object;
+                               $activity = self::createActivityFromItem($item['id'], true);
+                               // Only list "Create" activity objects here, no reshares
+                               if (is_array($activity['object']) && ($activity['type'] == 'Create')) {
+                                       $list[] = $activity['object'];
+                               }
                        }
 
                        if (!empty($list)) {
@@ -379,6 +381,15 @@ class Transmitter
 
                $terms = Term::tagArrayFromItemId($item['id'], [Term::MENTION, Term::IMPLICIT_MENTION]);
 
+               // Directly mention the original author upon a quoted reshare.
+               // Else just ensure that the original author receives the reshare.
+               $announce = self::getAnnounceArray($item);
+               if (!empty($announce['comment'])) {
+                       $data['to'][] = $announce['actor']['url'];
+               } elseif (!empty($announce)) {
+                       $data['cc'][] = $announce['actor']['url'];
+               }
+
                if (!$item['private']) {
                        $data = array_merge($data, self::fetchPermissionBlockFromConversation($item));
 
@@ -757,8 +768,8 @@ class Transmitter
 
                // Only check for a reshare, if it is a real reshare and no quoted reshare
                if (strpos($item['body'], "[share") === 0) {
-                       $announce = api_share_as_retweet($item);
-                       $reshared = !empty($announce['plink']);
+                       $announce = self::getAnnounceArray($item);
+                       $reshared = !empty($announce);
                }
 
                if ($reshared) {
@@ -919,29 +930,6 @@ class Transmitter
                /// @todo Create "conversation" entry
        }
 
-       /**
-        * Creates an object array for a given item id
-        *
-        * @param integer $item_id
-        *
-        * @return array with the object data
-        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
-        * @throws \ImagickException
-        */
-       public static function createObjectFromItemID($item_id)
-       {
-               $item = Item::selectFirst([], ['id' => $item_id, 'parent-network' => Protocol::NATIVE_SUPPORT]);
-
-               if (!DBA::isResult($item)) {
-                       return false;
-               }
-
-               $data = ['@context' => ActivityPub::CONTEXT];
-               $data = array_merge($data, self::createNote($item));
-
-               return $data;
-       }
-
        /**
         * Creates a location entry for a given item array
         *
@@ -1004,6 +992,13 @@ class Transmitter
                                $tags[] = ['type' => 'Mention', 'href' => $term['url'], 'name' => $mention];
                        }
                }
+
+               $announce = self::getAnnounceArray($item);
+               // Mention the original author upon commented reshares
+               if (!empty($announce['comment'])) {
+                       $tags[] = ['type' => 'Mention', 'href' => $announce['actor']['url'], 'name' => '@' . $announce['actor']['addr']];
+               }
+
                return $tags;
        }
 
@@ -1371,46 +1366,74 @@ class Transmitter
        private static function createAnnounce($item, $data)
        {
                $orig_body = $item['body'];
-               $announce = api_share_as_retweet($item);
-               if (empty($announce['plink'])) {
+               $announce = self::getAnnounceArray($item);
+               if (empty($announce)) {
                        $data['type'] = 'Create';
                        $data['object'] = self::createNote($item);
                        return $data;
                }
 
-               // Fetch the original id of the object
-               $activity = ActivityPub::fetchContent($announce['plink'], $item['uid']);
-               if (!empty($activity)) {
-                       $ldactivity = JsonLD::compact($activity);
-                       $id = JsonLD::fetchElement($ldactivity, '@id');
-                       $type = str_replace('as:', '', JsonLD::fetchElement($ldactivity, '@type'));
-                       if (!empty($id)) {
-                               if (empty($announce['share-pre-body'])) {
-                                       // Pure announce, without a quote
-                                       $data['type'] = 'Announce';
-                                       $data['object'] = $id;
-                                       return $data;
-                               }
-
-                               // Quote
-                               $data['type'] = 'Create';
-                               $item['body'] = trim($announce['share-pre-body']) . "\n" . $id;
-                               $data['object'] = self::createNote($item);
-
-                               /// @todo Finally descide how to implement this in AP. This is a possible way:
-                               $data['object']['attachment'][] = ['type' => $type, 'id' => $id];
-
-                               $data['object']['source']['content'] = $orig_body;
-                               return $data;
-                       }
+               if (empty($announce['comment'])) {
+                       // Pure announce, without a quote
+                       $data['type'] = 'Announce';
+                       $data['object'] = $announce['object']['uri'];
+                       return $data;
                }
 
-               $item['body'] = $orig_body;
+               // Quote
                $data['type'] = 'Create';
+               $item['body'] = $announce['comment'] . "\n" . $announce['object']['plink'];
                $data['object'] = self::createNote($item);
+
+               /// @todo Finally descide how to implement this in AP. This is a possible way:
+               $data['object']['attachment'][] = self::createNote($announce['object']);
+
+               $data['object']['source']['content'] = $orig_body;
                return $data;
        }
 
+       /**
+        * Return announce related data if the item is an annunce
+        *
+        * @param array $item
+        *
+        * @return array
+        */
+       public static function getAnnounceArray($item)
+       {
+               if (!preg_match("/(.*?)\[share(.*?)\]\s?.*?\s?\[\/share\]\s?/ism", $item['body'], $matches)) {
+                       return [];
+               }
+
+               $attributes = $matches[2];
+               $comment = $matches[1];
+
+               preg_match("/guid='(.*?)'/ism", $attributes, $matches);
+               if (empty($matches[1])) {
+                       preg_match('/guid="(.*?)"/ism', $attributes, $matches);
+               }
+
+               if (empty($matches[1])) {
+                       return [];
+               }
+
+               $reshared_item = Item::selectFirst([], ['guid' => $matches[1]]);
+               if (!DBA::isResult($reshared_item)) {
+                       return [];
+               }
+
+               if (!in_array($reshared_item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN])) {
+                       return [];
+               }
+
+               $profile = APContact::getByURL($reshared_item['author-link'], false);
+               if (empty($profile)) {
+                       return [];
+               }
+
+               return ['object' => $reshared_item, 'actor' => $profile, 'comment' => trim($comment)];
+       }
+
        /**
         * Creates an activity id for a given contact id
         *
index a4fd11662fd34c5fe38da7b5033aed93491cf01b..67fe10391043e71bc4e3a3327f9e9ea39845fe88 100644 (file)
@@ -374,6 +374,14 @@ return [
                // When the global community page is enabled, use this option to display a hint above the stream, that this is a collection of all public top-level postings that arrive on your node.
                'show_global_community_hint' => false,
 
+               // show_received (Boolean)
+               // Show the receive data along with the post creation date
+               'show_received' => true,
+
+               // show_received_seconds (Integer)
+               // Display the received date when the difference between received and created is higher than this.
+               'show_received_seconds' => 500,
+
                // show_unsupported_addons (Boolean)
                // Show all addons including the unsupported ones.
                'show_unsupported_addons' => false,
index 339860afe636588723491aca074d94b0fa5dea39..f5b44aec22c80d6c512c54e4c65de89baa42eb2f 100644 (file)
@@ -17,7 +17,7 @@ return [
 
        '/.well-known' => [
                '/host-meta'      => [Module\WellKnown\HostMeta::class,     [R::GET]],
-               '/nodeinfo[/1.0]' => [Module\NodeInfo::class,               [R::GET]],
+               '/nodeinfo'       => [Module\WellKnown\NodeInfo::class,     [R::GET]],
                '/webfinger'      => [Module\Xrd::class,                    [R::GET]],
                '/x-social-relay' => [Module\WellKnown\XSocialRelay::class, [R::GET]],
        ],
@@ -145,17 +145,17 @@ return [
                '/ignore/{id}' => [Module\Item\Ignore::class, [R::GET]],
        ],
 
-       '/like/{item:\d+}' => [Module\Like::class,            [R::GET]],
-       '/localtime'       => [Module\Debug\Localtime::class, [R::GET, R::POST]],
-       '/login'           => [Module\Login::class,           [R::GET, R::POST]],
-       '/logout'          => [Module\Logout::class,          [R::GET, R::POST]],
-       '/magic'           => [Module\Magic::class,           [R::GET]],
-       '/maintenance'     => [Module\Maintenance::class,     [R::GET]],
-       '/manifest'        => [Module\Manifest::class,        [R::GET]],
-       '/modexp/{nick}'   => [Module\PublicRSAKey::class,    [R::GET]],
-       '/newmember'       => [Module\Welcome::class,         [R::GET]],
-       '/nodeinfo/1.0'    => [Module\NodeInfo::class,        [R::GET]],
-       '/nogroup'         => [Module\Group::class,           [R::GET]],
+       '/like/{item:\d+}'    => [Module\Like::class,            [R::GET]],
+       '/localtime'          => [Module\Debug\Localtime::class, [R::GET, R::POST]],
+       '/login'              => [Module\Login::class,           [R::GET, R::POST]],
+       '/logout'             => [Module\Logout::class,          [R::GET, R::POST]],
+       '/magic'              => [Module\Magic::class,           [R::GET]],
+       '/maintenance'        => [Module\Maintenance::class,     [R::GET]],
+       '/manifest'           => [Module\Manifest::class,        [R::GET]],
+       '/modexp/{nick}'      => [Module\PublicRSAKey::class,    [R::GET]],
+       '/newmember'          => [Module\Welcome::class,         [R::GET]],
+       '/nodeinfo/{version}' => [Module\NodeInfo::class,        [R::GET]],
+       '/nogroup'            => [Module\Group::class,           [R::GET]],
 
        '/notify'         => [
                '[/]'            => [Module\Notifications\Notify::class, [R::GET]],
index 3410f3049df83a1660b9c7cd0c76ca1c773c653d..245529fb216ab835b5bbf386ca5f754815f8f6b1 100644 (file)
@@ -3775,16 +3775,6 @@ class ApiTest extends DatabaseTest
                $this->assertEquals('some_text [url="some_url"]"some_url"[/url]', $result);
        }
 
-       /**
-        * Test the api_clean_attachments() function.
-        *
-        * @return void
-        */
-       public function testApiCleanAttachments()
-       {
-               $this->markTestIncomplete();
-       }
-
        /**
         * Test the api_best_nickname() function.
         *
diff --git a/view/js/acl.js b/view/js/acl.js
deleted file mode 100644 (file)
index b50dbae..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPLv3-or-later
-function ACL(backend_url, preset, automention, is_mobile){
-
-       this.url = backend_url;
-       this.automention = automention;
-       this.is_mobile = is_mobile;
-
-
-       this.kp_timer = null;
-
-       if (preset == undefined) {
-               preset = [];
-       }
-       this.allow_cid = (preset[0] || []);
-       this.allow_gid = (preset[1] || []);
-       this.deny_cid  = (preset[2] || []);
-       this.deny_gid  = (preset[3] || []);
-       this.group_uids = [];
-       this.forumCache = null;
-
-       if (this.is_mobile) {
-               this.nw = 1;
-       } else {
-               this.nw = 4;
-       }
-
-
-       this.list_content = $("#acl-list-content");
-       this.item_tpl = unescape($(".acl-list-item[rel=acl-template]").html());
-       this.showall = $("#acl-showall");
-
-       if (preset.length==0) {
-               this.showall.addClass("selected");
-       }
-
-       /*events*/
-       this.showall.click(this.on_showall.bind(this));
-       $(document).on("click", ".acl-button-show", this.on_button_show.bind(this));
-       $(document).on("click", ".acl-button-hide", this.on_button_hide.bind(this));
-       $("#acl-search").keypress(this.on_search.bind(this));
-       $("#acl-wrapper").parents("form").submit(this.on_submit.bind(this));
-
-       /* add/remove mentions  */
-       this.element = $("#profile-jot-text");
-       this.htmlelm = this.element.get()[0];
-}
-
-ACL.prototype.remove_mention = function(id) {
-       if (!this.automention) {
-               return;
-       }
-       var nick = this.data[id].nick;
-       var addr = this.data[id].addr;
-
-       if (addr != "") {
-               var searchText = "!" + addr + " ";
-       } else {
-               var searchText = "!" + nick + "+" + id + " ";
-       }
-
-       var start = this.element.val().indexOf(searchText);
-       if (start < 0) {
-               return;
-       }
-       var end = start + searchText.length;
-       this.element.setSelection(start, end).replaceSelectedText('').collapseSelection(false);
-};
-
-ACL.prototype.add_mention = function(id) {
-       if (!this.automention) {
-               return;
-       }
-       var nick = this.data[id].nick;
-       var addr = this.data[id].addr;
-
-       if (addr != "") {
-               var searchText = "!" + addr + " ";
-       } else {
-               var searchText = "!" + nick + "+" + id + " ";
-       }
-
-       if (this.element.val().indexOf( searchText) >= 0 ) {
-               return;
-       }
-       this.element.val(searchText + this.element.val()).trigger('change');
-}
-
-ACL.prototype.on_submit = function(){
-       var aclfields = $("#acl-fields").html("");
-       $(this.allow_gid).each(function(i,v){
-               aclfields.append("<input type='hidden' name='group_allow[]' value='"+v+"'>");
-       });
-       $(this.allow_cid).each(function(i,v){
-               aclfields.append("<input type='hidden' name='contact_allow[]' value='"+v+"'>");
-       });
-       $(this.deny_gid).each(function(i,v){
-               aclfields.append("<input type='hidden' name='group_deny[]' value='"+v+"'>");
-       });
-       $(this.deny_cid).each(function(i,v){
-               aclfields.append("<input type='hidden' name='contact_deny[]' value='"+v+"'>");
-       });
-};
-
-ACL.prototype.search = function(){
-       var srcstr = $("#acl-search").val();
-       this.list_content.html("");
-       this.get(0,100, srcstr);
-};
-
-ACL.prototype.on_search = function(event){
-       if (this.kp_timer) clearTimeout(this.kp_timer);
-
-       // Triggers an immediate search while preventing form submission
-       if (event.key === 'Enter') {
-               this.search();
-               event.preventDefault();
-       } else {
-               this.kp_timer = setTimeout( this.search.bind(this), 500);
-       }
-};
-
-ACL.prototype.on_showall = function(event){
-       event.preventDefault()
-       event.stopPropagation();
-
-       if (this.showall.hasClass("selected")){
-               return false;
-       }
-       this.showall.addClass("selected");
-
-       this.allow_cid = [];
-       this.allow_gid = [];
-       this.deny_cid  = [];
-       this.deny_gid  = [];
-
-       this.update_view();
-
-       return false;
-};
-
-ACL.prototype.on_button_show = function(event){
-       event.preventDefault()
-       event.stopImmediatePropagation()
-       event.stopPropagation();
-
-       this.set_allow($(event.target).parent().attr('id'));
-
-       return false;
-};
-
-ACL.prototype.on_button_hide = function(event){
-       event.preventDefault()
-       event.stopImmediatePropagation()
-       event.stopPropagation();
-
-       this.set_deny($(event.target).parent().attr('id'));
-
-       return false;
-};
-
-ACL.prototype.set_allow = function(itemid) {
-       type = itemid[0];
-       id   = parseInt(itemid.substr(1));
-
-       switch (type){
-               case "g":
-                       if (this.allow_gid.indexOf(id) < 0) {
-                               this.allow_gid.push(id);
-                       }else {
-                               this.allow_gid.remove(id);
-                       }
-                       if (this.deny_gid.indexOf(id) >= 0) {
-                               this.deny_gid.remove(id);
-                       }
-                       break;
-               case "c":
-                       if (this.allow_cid.indexOf(id) < 0){
-                               this.allow_cid.push(id);
-                               if (this.data[id].forum == "1") {
-                                       // If we have select already a forum,
-                                       // we need to remove the old one (because friendica does
-                                       // allow only one forum as receiver).
-                                       if (this.forumCache !== null && this.forumCache !== id) {
-                                               this.deselectCid(this.forumCache);
-                                       }
-                                       // Update the forum cache.
-                                       this.forumCache = id;
-                                       this.add_mention(id);
-                               }
-                       } else {
-                               this.allow_cid.remove(id);
-                               if (this.data[id].forum == "1") {
-                                       this.remove_mention(id);
-                               }
-                       }
-                       if (this.deny_cid.indexOf(id) >=0 ) {
-                               this.deny_cid.remove(id);
-                       }
-                       break;
-       }
-       this.update_view();
-};
-
-ACL.prototype.set_deny = function(itemid){
-       type = itemid[0];
-       id     = parseInt(itemid.substr(1));
-
-       switch(type){
-               case "g":
-                       if (this.deny_gid.indexOf(id)<0){
-                               this.deny_gid.push(id)
-                       } else {
-                               this.deny_gid.remove(id);
-                       }
-                       if (this.allow_gid.indexOf(id)>=0) this.allow_gid.remove(id);
-                       break;
-               case "c":
-                       if (this.data[id].forum=="1") this.remove_mention(id);
-                       if (this.deny_cid.indexOf(id)<0){
-                               this.deny_cid.push(id)
-                       } else {
-                               this.deny_cid.remove(id);
-                       }
-                       if (this.allow_cid.indexOf(id)>=0) this.allow_cid.remove(id);
-                       break;
-       }
-       this.update_view();
-};
-
-ACL.prototype.is_show_all = function() {
-       return (this.allow_gid.length==0 && this.allow_cid.length==0 &&
-               this.deny_gid.length==0 && this.deny_cid.length==0);
-};
-
-ACL.prototype.update_view = function () {
-       if (this.is_show_all()) {
-               this.showall.addClass("selected");
-               /* jot acl */
-               $('#jot-perms-icon').removeClass('lock').addClass('unlock');
-               $('#jot-public').show();
-               $('.profile-jot-net input[type=checkbox]').each(function() {
-                       // Restores checkbox state if it had been saved
-                       if ($(this).attr('data-checked') !== undefined) {
-                               $(this).prop('checked', $(this).attr('data-checked') === 'true');
-                       }
-               });
-
-               $('.profile-jot-net input').attr('disabled', false);
-               if (typeof editor != 'undefined' && editor != false) {
-                       $('#profile-jot-desc').html(ispublic);
-               }
-       } else {
-               this.showall.removeClass("selected");
-               /* jot acl */
-               $('#jot-perms-icon').removeClass('unlock').addClass('lock');
-               $('#jot-public').hide();
-               $('.profile-jot-net input[type=checkbox]').each(function() {
-                       // Saves current checkbox state
-                       $(this)
-                               .attr('data-checked', $(this).prop('checked'))
-                               .prop('checked', false);
-               });
-               $('.profile-jot-net input').attr('disabled', 'disabled');
-               $('#profile-jot-desc').html('&nbsp;');
-       }
-
-       $("#acl-list-content .acl-list-item").each(function (index, element) {
-               $(this).removeClass("groupshow grouphide");
-
-               itemid = $(element).attr('id');
-               type = itemid[0];
-               id       = parseInt(itemid.substr(1));
-
-               btshow = $(element).children(".acl-button-show").removeClass("selected");
-               bthide = $(element).children(".acl-button-hide").removeClass("selected");
-
-               switch (type) {
-                       case "g":
-                               var uclass = "";
-                               if (this.allow_gid.indexOf(id) >= 0) {
-                                       btshow.addClass("selected");
-                                       bthide.removeClass("selected");
-                                       uclass = "groupshow";
-                               }
-                               if (this.deny_gid.indexOf(id) >= 0) {
-                                       btshow.removeClass("selected");
-                                       bthide.addClass("selected");
-                                       uclass = "grouphide";
-                               }
-
-                               $(this.group_uids[id]).each(function (i, v) {
-                                       if (uclass == "grouphide")
-                                               $("#c" + v).removeClass("groupshow");
-                                       if (uclass != "") {
-                                               var cls = $("#c" + v).attr('class');
-                                               if (cls == undefined)
-                                                       return true;
-                                               var hiding = cls.indexOf('grouphide');
-                                               if (hiding == -1)
-                                                       $("#c" + v).addClass(uclass);
-                                       }
-                               });
-
-                               break;
-                       case "c":
-                               if (this.allow_cid.indexOf(id) >= 0) {
-                                       btshow.addClass("selected");
-                                       bthide.removeClass("selected");
-                               }
-                               if (this.deny_cid.indexOf(id) >= 0) {
-                                       btshow.removeClass("selected");
-                                       bthide.addClass("selected");
-                               }
-               }
-
-       }.bind(this));
-
-};
-
-ACL.prototype.get = function(start,count, search){
-       var postdata = {
-               start:start,
-               count:count,
-               search:search,
-       }
-
-       $.ajax({
-               type:'POST',
-               url: this.url,
-               data: postdata,
-               dataType: 'json',
-               success:this.populate.bind(this)
-       });
-};
-
-ACL.prototype.populate = function(data){
-       var height = Math.ceil(data.tot / this.nw) * 42;
-       this.list_content.height(height);
-       this.data = {};
-       $(data.items).each(function(index, item) {
-               if (item.separator != undefined) {
-                       html = "<hr class='clear'>";
-               } else {
-                       html = "<div class='acl-list-item {4} {5} type{2}' title='{6}' id='{2}{3}'>"+this.item_tpl+"</div>";
-                       html = html.format(item.photo, item.name, item.type, item.id, (item.forum=='1'?'forum':''), item.network, item.link);
-                       if (item.uids != undefined) {
-                               this.group_uids[item.id] = item.uids;
-                       }
-               }
-               this.list_content.append(html);
-               this.data[item.id] = item;
-       }.bind(this));
-       $(".acl-list-item img[data-src]", this.list_content).each(function(i, el){
-               // Add src attribute for images with a data-src attribute
-               $(el).attr('src', $(el).data("src"));
-       });
-
-       this.update_view();
-};
-
-/**
- * @brief Deselect previous selected contact.
- *
- * @param {int} id The contact ID.
- * @returns {void}
- */
-ACL.prototype.deselectCid = function(id) {
-       if (this.allow_cid.indexOf(id) >= 0) {
-               this.allow_cid.remove(id);
-       }
-       if (this.deny_cid.indexOf(id) >=0 ) {
-               this.deny_cid.remove(id);
-       }
-       this.remove_mention(id);
-};
-// @license-end
diff --git a/view/js/friendica-tagsinput/LICENSE b/view/js/friendica-tagsinput/LICENSE
new file mode 100644 (file)
index 0000000..58bc985
--- /dev/null
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Tim Schlechter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/view/js/friendica-tagsinput/friendica-tagsinput-typeahead.css b/view/js/friendica-tagsinput/friendica-tagsinput-typeahead.css
new file mode 100644 (file)
index 0000000..8cec654
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * friendica-tagsinput v0.8.0
+ * 
+ */
+
+.twitter-typeahead .tt-query,
+.twitter-typeahead .tt-hint {
+    margin-bottom: 0;
+}
+
+.twitter-typeahead .tt-hint
+{
+    display: none;
+}
+
+.tt-menu {
+    position: absolute;
+    top: 100%;
+    left: 0;
+    z-index: 1000;
+    display: none;
+    float: left;
+    min-width: 160px;
+    padding: 5px 0;
+    margin: 2px 0 0;
+    list-style: none;
+    font-size: 14px;
+    background-color: #ffffff;
+    border: 1px solid #cccccc;
+    border: 1px solid rgba(0, 0, 0, 0.15);
+    border-radius: 4px;
+    -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+    background-clip: padding-box;
+    cursor: pointer;
+}
+
+.tt-suggestion {
+    display: block;
+    padding: 3px 20px;
+    clear: both;
+    font-weight: normal;
+    line-height: 1.428571429;
+    color: #333333;
+    white-space: nowrap;
+}
+
+.tt-suggestion:hover,
+.tt-suggestion:focus {
+    color: #ffffff;
+    text-decoration: none;
+    outline: 0;
+    background-color: #428bca;
+}
diff --git a/view/js/friendica-tagsinput/friendica-tagsinput.css b/view/js/friendica-tagsinput/friendica-tagsinput.css
new file mode 100644 (file)
index 0000000..6ad1d00
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * friendica-tagsinput v0.8.0
+ *
+ * Non-Bootstrap edition
+ */
+
+.label {
+       display: inline;
+       padding: .2em .6em .3em;
+       font-size: 75%;
+       font-weight: 700;
+       line-height: 1;
+       color: #fff;
+       text-align: center;
+       white-space: nowrap;
+       vertical-align: baseline;
+       border-radius: .25em;
+}
+
+.label-default {
+       background-color: #777777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+       background-color: #5e5e5e;
+}
+.label-primary {
+       background-color: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+       background-color: #286090;
+}
+.label-success {
+       background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+       background-color: #449d44;
+}
+.label-info {
+       background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+       background-color: #31b0d5;
+}
+.label-warning {
+       background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+       background-color: #ec971f;
+}
+.label-danger {
+       background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+       background-color: #c9302c;
+}
+
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+       background-color: #eeeeee;
+       opacity: 1;
+}
+.form-control[disabled],
+fieldset[disabled] .form-control {
+       cursor: not-allowed;
+}
+
+
+
+
+.friendica-tagsinput {
+       background-color: #fff;
+       border: 1px solid #ccc;
+       box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+       display: inline-block;
+       padding: 4px 6px;
+       color: #555;
+       vertical-align: middle;
+       border-radius: 4px;
+       max-width: 100%;
+       line-height: 22px;
+       cursor: text;
+       height: auto;
+}
+
+.friendica-tagsinput.input-lg {
+       line-height: 27px;
+}
+
+.friendica-tagsinput input {
+       border: none;
+       box-shadow: none;
+       outline: none;
+       background-color: transparent;
+       padding: 0 6px;
+       margin: 0;
+       width: auto;
+       max-width: inherit;
+}
+
+.friendica-tagsinput.form-control input::-moz-placeholder {
+       color: #777;
+       opacity: 1;
+}
+
+.friendica-tagsinput.form-control input:-ms-input-placeholder {
+       color: #777;
+}
+
+.friendica-tagsinput.form-control input::-webkit-input-placeholder {
+       color: #777;
+}
+
+.friendica-tagsinput input:focus {
+       border: none;
+       box-shadow: none;
+}
+
+.friendica-tagsinput .tag {
+       margin: 0 2px 2px 0;
+       color: white;
+       font-weight: normal;
+}
+
+.friendica-tagsinput .tag img {
+       width: auto;
+       height: 1.5em;
+       vertical-align: text-top;
+       margin-right: 8px;
+}
+
+.friendica-tagsinput .tag [data-role="remove"] {
+       margin-left: 8px;
+       cursor: pointer;
+}
+
+.friendica-tagsinput .tag [data-role="remove"]:after {
+       content: "x";
+       padding: 0px 2px;
+       font-weight: bold;
+}
+
+.friendica-tagsinput .tag [data-role="remove"]:hover {
+       box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.friendica-tagsinput .tag [data-role="remove"]:hover:active {
+       box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
diff --git a/view/js/friendica-tagsinput/friendica-tagsinput.js b/view/js/friendica-tagsinput/friendica-tagsinput.js
new file mode 100644 (file)
index 0000000..af722d7
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * friendica-tagsinput v0.8.0
+ * Based on bootstrap-tagsinput v0.8.0
+ *
+ * Adds:
+ * - optional thumbnail
+ * - copying source input element class to the pseudo-input element
+ *
+ */
+
+(function ($) {
+  "use strict";
+
+  var defaultOptions = {
+    tagClass: function(item) {
+      return 'label label-info';
+    },
+    focusClass: 'focus',
+    itemValue: function(item) {
+      return item ? item.toString() : item;
+    },
+    itemText: function(item) {
+      return this.itemValue(item);
+    },
+    itemTitle: function(item) {
+      return null;
+    },
+    itemThumb: function(item) {
+      return null;
+    },
+    freeInput: true,
+    addOnBlur: true,
+    maxTags: undefined,
+    maxChars: undefined,
+    confirmKeys: [13, 44],
+    delimiter: ',',
+    delimiterRegex: null,
+    cancelConfirmKeysOnEmpty: false,
+    onTagExists: function(item, $tag) {
+      $tag.hide().fadeIn();
+    },
+    trimValue: false,
+    allowDuplicates: false,
+    triggerChange: true
+  };
+
+  /**
+   * Constructor function
+   */
+  function TagsInput(element, options) {
+    this.isInit = true;
+    this.itemsArray = [];
+
+    this.$element = $(element);
+    this.$element.hide();
+
+    this.isSelect = (element.tagName === 'SELECT');
+    this.multiple = (this.isSelect && element.hasAttribute('multiple'));
+    this.objectItems = options && options.itemValue;
+    this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
+    this.inputSize = Math.max(1, this.placeholderText.length);
+
+    this.$container = $('<div class="friendica-tagsinput"></div>');
+    this.$container.addClass(this.$element.attr('class'));
+    this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
+
+    this.$element.before(this.$container);
+
+    this.build(options);
+    this.isInit = false;
+  }
+
+  TagsInput.prototype = {
+    constructor: TagsInput,
+
+    /**
+     * Adds the given item as a new tag. Pass true to dontPushVal to prevent
+     * updating the elements val()
+     */
+    add: function(item, dontPushVal, options) {
+      let self = this;
+
+      if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
+        return;
+
+      // Ignore falsey values, except false
+      if (item !== false && !item)
+        return;
+
+      // Trim value
+      if (typeof item === "string" && self.options.trimValue) {
+        item = $.trim(item);
+      }
+
+      // Throw an error when trying to add an object while the itemValue option was not set
+      if (typeof item === "object" && !self.objectItems)
+        throw("Can't add objects when itemValue option is not set");
+
+      // Ignore strings only containg whitespace
+      if (item.toString().match(/^\s*$/))
+        return;
+
+      // If SELECT but not multiple, remove current tag
+      if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
+        self.remove(self.itemsArray[0]);
+
+      if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
+        var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
+        var items = item.split(delimiter);
+        if (items.length > 1) {
+          for (var i = 0; i < items.length; i++) {
+            this.add(items[i], true);
+          }
+
+          if (!dontPushVal)
+            self.pushVal(self.options.triggerChange);
+          return;
+        }
+      }
+
+      var itemValue = self.options.itemValue(item),
+          itemText = self.options.itemText(item),
+          tagClass = self.options.tagClass(item),
+          itemTitle = self.options.itemTitle(item),
+          itemThumb = self.options.itemThumb(item);
+
+      // Ignore items allready added
+      var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
+      if (existing && !self.options.allowDuplicates) {
+        // Invoke onTagExists
+        if (self.options.onTagExists) {
+          var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
+          self.options.onTagExists(item, $existingTag);
+        }
+        return;
+      }
+
+      // if length greater than limit
+      if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
+        return;
+
+      // raise beforeItemAdd arg
+      var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options});
+      self.$element.trigger(beforeItemAddEvent);
+      if (beforeItemAddEvent.cancel)
+        return;
+
+      // register item in internal array and map
+      self.itemsArray.push(item);
+
+      // add a tag element
+      var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' +
+          (itemThumb !== null ? '<img src="' + itemThumb + '" alt="">' : '') +
+          htmlEncode(itemText) + '<span data-role="remove"></span>' +
+          '</span>');
+      $tag.data('item', item);
+      self.findInputWrapper().before($tag);
+      $tag.after(' ');
+
+      // Check to see if the tag exists in its raw or uri-encoded form
+      var optionExists = (
+          $('option[value="' + encodeURIComponent(itemValue) + '"]', self.$element).length ||
+          $('option[value="' + htmlEncode(itemValue) + '"]', self.$element).length
+      );
+
+      // add <option /> if item represents a value not present in one of the <select />'s options
+      if (self.isSelect && !optionExists) {
+        var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
+        $option.data('item', item);
+        $option.attr('value', itemValue);
+        self.$element.append($option);
+      }
+
+      if (!dontPushVal)
+        self.pushVal(self.options.triggerChange);
+
+      // Add class when reached maxTags
+      if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
+        self.$container.addClass('friendica-tagsinput-max');
+
+      // If using typeahead, once the tag has been added, clear the typeahead value so it does not stick around in the input.
+      if ($('.typeahead, .twitter-typeahead', self.$container).length) {
+        self.$input.typeahead('val', '');
+      }
+
+      if (this.isInit) {
+        self.$element.trigger($.Event('itemAddedOnInit', { item: item, options: options }));
+      } else {
+        self.$element.trigger($.Event('itemAdded', { item: item, options: options }));
+      }
+    },
+
+    /**
+     * Removes the given item. Pass true to dontPushVal to prevent updating the
+     * elements val()
+     */
+    remove: function(item, dontPushVal, options) {
+      var self = this;
+
+      if (self.objectItems) {
+        if (typeof item === "object")
+          item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) ==  self.options.itemValue(item); } );
+        else
+          item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) ==  item; } );
+
+        item = item[item.length-1];
+      }
+
+      if (item) {
+        var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options });
+        self.$element.trigger(beforeItemRemoveEvent);
+        if (beforeItemRemoveEvent.cancel)
+          return;
+
+        $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
+        $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
+        if($.inArray(item, self.itemsArray) !== -1)
+          self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
+      }
+
+      if (!dontPushVal)
+        self.pushVal(self.options.triggerChange);
+
+      // Remove class when reached maxTags
+      if (self.options.maxTags > self.itemsArray.length)
+        self.$container.removeClass('friendica-tagsinput-max');
+
+      self.$element.trigger($.Event('itemRemoved',  { item: item, options: options }));
+    },
+
+    /**
+     * Removes all items
+     */
+    removeAll: function() {
+      var self = this;
+
+      $('.tag', self.$container).remove();
+      $('option', self.$element).remove();
+
+      while(self.itemsArray.length > 0)
+        self.itemsArray.pop();
+
+      self.pushVal(self.options.triggerChange);
+    },
+
+    /**
+     * Refreshes the tags so they match the text/value of their corresponding
+     * item.
+     */
+    refresh: function() {
+      var self = this;
+      $('.tag', self.$container).each(function() {
+        var $tag = $(this),
+            item = $tag.data('item'),
+            itemValue = self.options.itemValue(item),
+            itemText = self.options.itemText(item),
+            tagClass = self.options.tagClass(item);
+
+          // Update tag's class and inner text
+          $tag.attr('class', null);
+          $tag.addClass('tag ' + htmlEncode(tagClass));
+          $tag.contents().filter(function() {
+            return this.nodeType == 3;
+          })[0].nodeValue = htmlEncode(itemText);
+
+          if (self.isSelect) {
+            var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
+            option.attr('value', itemValue);
+          }
+      });
+    },
+
+    /**
+     * Returns the items added as tags
+     */
+    items: function() {
+      return this.itemsArray;
+    },
+
+    /**
+     * Assembly value by retrieving the value of each item, and set it on the
+     * element.
+     */
+    pushVal: function() {
+      var self = this,
+          val = $.map(self.items(), function(item) {
+            return self.options.itemValue(item).toString();
+          });
+
+      self.$element.val(val, true);
+
+      if (self.options.triggerChange)
+        self.$element.trigger('change');
+    },
+
+    /**
+     * Initializes the tags input behaviour on the element
+     */
+    build: function(options) {
+      var self = this;
+
+      self.options = $.extend({}, defaultOptions, options);
+      // When itemValue is set, freeInput should always be false
+      if (self.objectItems)
+        self.options.freeInput = false;
+
+      makeOptionItemFunction(self.options, 'itemValue');
+      makeOptionItemFunction(self.options, 'itemText');
+      makeOptionItemFunction(self.options, 'itemThumb');
+      makeOptionFunction(self.options, 'tagClass');
+
+      // Typeahead Bootstrap version 2.3.2
+      if (self.options.typeahead) {
+        var typeahead = self.options.typeahead || {};
+
+        makeOptionFunction(typeahead, 'source');
+
+        self.$input.typeahead($.extend({}, typeahead, {
+          source: function (query, process) {
+            function processItems(items) {
+              var texts = [];
+
+              for (var i = 0; i < items.length; i++) {
+                var text = self.options.itemText(items[i]);
+                map[text] = items[i];
+                texts.push(text);
+              }
+              process(texts);
+            }
+
+            this.map = {};
+            var map = this.map,
+                data = typeahead.source(query);
+
+            if ($.isFunction(data.success)) {
+              // support for Angular callbacks
+              data.success(processItems);
+            } else if ($.isFunction(data.then)) {
+              // support for Angular promises
+              data.then(processItems);
+            } else {
+              // support for functions and jquery promises
+              $.when(data)
+                  .then(processItems);
+            }
+          },
+          updater: function (text) {
+            self.add(this.map[text]);
+            return this.map[text];
+          },
+          matcher: function (text) {
+            return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
+          },
+          sorter: function (texts) {
+            return texts.sort();
+          },
+          highlighter: function (text) {
+            var regex = new RegExp( '(' + this.query + ')', 'gi' );
+            return text.replace( regex, "<strong>$1</strong>" );
+          }
+        }));
+      }
+
+      // typeahead.js
+      if (self.options.typeaheadjs) {
+        var typeaheadConfig = null;
+        var typeaheadDatasets = {};
+
+        // Determine if main configurations were passed or simply a dataset
+        var typeaheadjs = self.options.typeaheadjs;
+        if ($.isArray(typeaheadjs)) {
+          typeaheadConfig = typeaheadjs[0];
+          typeaheadDatasets = typeaheadjs[1];
+        } else {
+          typeaheadDatasets = typeaheadjs;
+        }
+
+        self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
+          if (typeaheadDatasets.valueKey)
+            self.add(datum[typeaheadDatasets.valueKey]);
+          else
+            self.add(datum);
+          self.$input.typeahead('val', '');
+        }, self));
+      }
+
+      self.$container.on('click', $.proxy(function(event) {
+        if (! self.$element.attr('disabled')) {
+          self.$input.removeAttr('disabled');
+        }
+        self.$input.focus();
+      }, self));
+
+      if (self.options.addOnBlur && self.options.freeInput) {
+        self.$input.on('focusout', $.proxy(function(event) {
+          // HACK: only process on focusout when no typeahead opened, to
+          //       avoid adding the typeahead text as tag
+          if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
+            self.add(self.$input.val());
+            self.$input.val('');
+          }
+        }, self));
+      }
+
+      // Toggle the 'focus' css class on the container when it has focus
+      self.$container.on({
+        focusin: function() {
+          self.$container.addClass(self.options.focusClass);
+        },
+        focusout: function() {
+          self.$container.removeClass(self.options.focusClass);
+        },
+      });
+
+      self.$container.on('keydown', 'input', $.proxy(function(event) {
+        var $input = $(event.target),
+            $inputWrapper = self.findInputWrapper();
+
+        if (self.$element.attr('disabled')) {
+          self.$input.attr('disabled', 'disabled');
+          return;
+        }
+
+        switch (event.which) {
+            // BACKSPACE
+          case 8:
+            if (doGetCaretPosition($input[0]) === 0) {
+              var prev = $inputWrapper.prev();
+              if (prev.length) {
+                self.remove(prev.data('item'));
+              }
+            }
+            break;
+
+            // DELETE
+          case 46:
+            if (doGetCaretPosition($input[0]) === 0) {
+              var next = $inputWrapper.next();
+              if (next.length) {
+                self.remove(next.data('item'));
+              }
+            }
+            break;
+
+            // LEFT ARROW
+          case 37:
+            // Try to move the input before the previous tag
+            var $prevTag = $inputWrapper.prev();
+            if ($input.val().length === 0 && $prevTag[0]) {
+              $prevTag.before($inputWrapper);
+              $input.focus();
+            }
+            break;
+            // RIGHT ARROW
+          case 39:
+            // Try to move the input after the next tag
+            var $nextTag = $inputWrapper.next();
+            if ($input.val().length === 0 && $nextTag[0]) {
+              $nextTag.after($inputWrapper);
+              $input.focus();
+            }
+            break;
+          default:
+            // ignore
+        }
+
+        // Reset internal input's size
+        var textLength = $input.val().length,
+            wordSpace = Math.ceil(textLength / 5),
+            size = textLength + wordSpace + 1;
+        $input.attr('size', Math.max(this.inputSize, $input.val().length));
+      }, self));
+
+      self.$container.on('keypress', 'input', $.proxy(function(event) {
+        var $input = $(event.target);
+
+        if (self.$element.attr('disabled')) {
+          self.$input.attr('disabled', 'disabled');
+          return;
+        }
+
+        var text = $input.val(),
+            maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
+        if (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached) {
+          // Only attempt to add a tag if there is data in the field
+          if (self.options.freeInput && text.length !== 0) {
+            self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
+            $input.val('');
+          }
+
+          // If the field is empty, let the event triggered fire as usual
+          if (self.options.cancelConfirmKeysOnEmpty === false) {
+            event.preventDefault();
+          }
+        }
+
+        // Reset internal input's size
+        var textLength = $input.val().length,
+            wordSpace = Math.ceil(textLength / 5),
+            size = textLength + wordSpace + 1;
+        $input.attr('size', Math.max(this.inputSize, $input.val().length));
+      }, self));
+
+      // Remove icon clicked
+      self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
+        if (self.$element.attr('disabled')) {
+          return;
+        }
+        self.remove($(event.target).closest('.tag').data('item'));
+      }, self));
+
+      // Only add existing value as tags when using strings as tags
+      if (self.options.itemValue === defaultOptions.itemValue) {
+        if (self.$element[0].tagName === 'INPUT') {
+          self.add(self.$element.val());
+        } else {
+          $('option', self.$element).each(function() {
+            self.add($(this).attr('value'), true);
+          });
+        }
+      }
+    },
+
+    /**
+     * Removes all tagsinput behaviour and unregsiter all event handlers
+     */
+    destroy: function() {
+      var self = this;
+
+      // Unbind events
+      self.$container.off('keypress', 'input');
+      self.$container.off('click', '[role=remove]');
+
+      self.$container.remove();
+      self.$element.removeData('tagsinput');
+      self.$element.show();
+    },
+
+    /**
+     * Sets focus on the tagsinput
+     */
+    focus: function() {
+      this.$input.focus();
+    },
+
+    /**
+     * Returns the internal input element
+     */
+    input: function() {
+      return this.$input;
+    },
+
+    /**
+     * Returns the element which is wrapped around the internal input. This
+     * is normally the $container, but typeahead.js moves the $input element.
+     */
+    findInputWrapper: function() {
+      var elt = this.$input[0],
+          container = this.$container[0];
+      while(elt && elt.parentNode !== container)
+        elt = elt.parentNode;
+
+      return $(elt);
+    }
+  };
+
+  /**
+   * Register JQuery plugin
+   */
+  $.fn.tagsinput = function(arg1, arg2, arg3) {
+    var results = [];
+
+    this.each(function() {
+      var tagsinput = $(this).data('tagsinput');
+      // Initialize a new tags input
+      if (!tagsinput) {
+          tagsinput = new TagsInput(this, arg1);
+          $(this).data('tagsinput', tagsinput);
+          results.push(tagsinput);
+
+          if (this.tagName === 'SELECT') {
+              $('option', $(this)).attr('selected', 'selected');
+          }
+
+          // Init tags from $(this).val()
+          $(this).val($(this).val());
+      } else if (!arg1 && !arg2) {
+          // tagsinput already exists
+          // no function, trying to init
+          results.push(tagsinput);
+      } else if(tagsinput[arg1] !== undefined) {
+          // Invoke function on existing tags input
+            if(tagsinput[arg1].length === 3 && arg3 !== undefined){
+               var retVal = tagsinput[arg1](arg2, null, arg3);
+            }else{
+               var retVal = tagsinput[arg1](arg2);
+            }
+          if (retVal !== undefined)
+              results.push(retVal);
+      }
+    });
+
+    if ( typeof arg1 == 'string') {
+      // Return the results from the invoked function calls
+      return results.length > 1 ? results : results[0];
+    } else {
+      return results;
+    }
+  };
+
+  $.fn.tagsinput.Constructor = TagsInput;
+
+  /**
+   * Most options support both a string or number as well as a function as
+   * option value. This function makes sure that the option with the given
+   * key in the given options is wrapped in a function
+   */
+  function makeOptionItemFunction(options, key) {
+    if (typeof options[key] !== 'function') {
+      var propertyName = options[key];
+      options[key] = function(item) { return item[propertyName]; };
+    }
+  }
+  function makeOptionFunction(options, key) {
+    if (typeof options[key] !== 'function') {
+      var value = options[key];
+      options[key] = function() { return value; };
+    }
+  }
+  /**
+   * HtmlEncodes the given value
+   */
+  var htmlEncodeContainer = $('<div />');
+  function htmlEncode(value) {
+    if (value) {
+      return htmlEncodeContainer.text(value).html();
+    } else {
+      return '';
+    }
+  }
+
+  /**
+   * Returns the position of the caret in the given input field
+   * http://flightschool.acylt.com/devnotes/caret-position-woes/
+   */
+  function doGetCaretPosition(oField) {
+    var iCaretPos = 0;
+    if (document.selection) {
+      oField.focus ();
+      var oSel = document.selection.createRange();
+      oSel.moveStart ('character', -oField.value.length);
+      iCaretPos = oSel.text.length;
+    } else if (oField.selectionStart || oField.selectionStart == '0') {
+      iCaretPos = oField.selectionStart;
+    }
+    return (iCaretPos);
+  }
+
+  /**
+    * Returns boolean indicates whether user has pressed an expected key combination.
+    * @param object keyPressEvent: JavaScript event object, refer
+    *     http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+    * @param object lookupList: expected key combinations, as in:
+    *     [13, {which: 188, shiftKey: true}]
+    */
+  function keyCombinationInList(keyPressEvent, lookupList) {
+      var found = false;
+      $.each(lookupList, function (index, keyCombination) {
+          if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
+              found = true;
+              return false;
+          }
+
+          if (keyPressEvent.which === keyCombination.which) {
+              var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
+                  shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
+                  ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
+              if (alt && shift && ctrl) {
+                  found = true;
+                  return false;
+              }
+          }
+      });
+
+      return found;
+  }
+
+  /**
+   * Initialize tagsinput behaviour on inputs and selects which have
+   * data-role=tagsinput
+   */
+  $(function() {
+    $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
+  });
+})(window.jQuery);
index 09493eebad3d1e4066e40358bd66390c214e42b4..f7278ce5b20fd2fe0fcb39d1d9e47b76d382bd23 100644 (file)
        $.fn.linkPreview = function (options) {
                var opts = jQuery.extend({}, $.fn.linkPreview.defaults, options);
 
-               var selector = $(this).selector;
-               selector = selector.substr(1);
+               var id = $(this).attr('id');
 
                var previewTpl = '\
-                       <div id="preview_' + selector + '" class="preview {0}">\
+                       <div id="preview_' + id + '" class="preview {0}">\
                                {1}\
-                               <input type="hidden" name="has_attachment" id="hasAttachment_' + selector + '" value="{2}" />\
-                               <input type="hidden" name="attachment_url" id="attachmentUrl_' + selector + '" value="{3}" />\
-                               <input type="hidden" name="attachment_type" id="attachmentType_' + selector + '" value="{4}" />\
+                               <input type="hidden" name="has_attachment" id="hasAttachment_' + id + '" value="{2}" />\
+                               <input type="hidden" name="attachment_url" id="attachmentUrl_' + id + '" value="{3}" />\
+                               <input type="hidden" name="attachment_type" id="attachmentType_' + id + '" value="{4}" />\
                        </div>';
 
                var attachmentTpl = '\
                        <hr class="previewseparator">\
-                       <div id="closePreview_' + selector + '" title="Remove" class="closePreview" >\
+                       <div id="closePreview_' + id + '" title="Remove" class="closePreview" >\
                                <button type="button" class="previewActionBtn">×</button>\
                        </div>\
-                       <div id="previewImages_' + selector + '" class="previewImages">\
-                               <div id="previewImgBtn_' + selector + '" class="previewImgBtn">\
-                                       <button type="button" id="previewChangeImg_' + selector + '" class="buttonChangeDeactive previewActionBtn" style="display: none">\
+                       <div id="previewImages_' + id + '" class="previewImages">\
+                               <div id="previewImgBtn_' + id + '" class="previewImgBtn">\
+                                       <button type="button" id="previewChangeImg_' + id + '" class="buttonChangeDeactive previewActionBtn" style="display: none">\
                                                <i class="fa fa-exchange" aria-hidden="true"></i>\
                                        </button>\
                                </div>\
-                               <div id="previewImage_' + selector + '" class="previewImage">\
+                               <div id="previewImage_' + id + '" class="previewImage">\
                                </div>\
-                               <input type="hidden" id="photoNumber_' + selector + '" class="photoNumber" value="0" />\
-                               <input type="hidden" name="attachment_img_src" id="attachmentImageSrc_' + selector + '" value="" />\
-                               <input type="hidden" name="attachment_img_width" id="attachmentImageWidth_' + selector + '" value="0" />\
-                               <input type="hidden" name="attachment_img_height" id="attachmentImageHeight_' + selector + '" value="0" />\
+                               <input type="hidden" id="photoNumber_' + id + '" class="photoNumber" value="0" />\
+                               <input type="hidden" name="attachment_img_src" id="attachmentImageSrc_' + id + '" value="" />\
+                               <input type="hidden" name="attachment_img_width" id="attachmentImageWidth_' + id + '" value="0" />\
+                               <input type="hidden" name="attachment_img_height" id="attachmentImageHeight_' + id + '" value="0" />\
                        </div>\
-                       <div id="previewContent_' + selector + '" class="previewContent">\
-                               <h4 id="previewTitle_' + selector + '" class="previewTitle"></h4>\
-                               <blockquote id="previewDescription_' + selector + '" class="previewDescription"></blockquote>\
-                               <div id="hiddenDescription_' + selector + '" class="hiddenDescription"></div>\
-                               <sup id="previewUrl_' + selector + '" class="previewUrl"></sup>\
+                       <div id="previewContent_' + id + '" class="previewContent">\
+                               <h4 id="previewTitle_' + id + '" class="previewTitle"></h4>\
+                               <blockquote id="previewDescription_' + id + '" class="previewDescription"></blockquote>\
+                               <div id="hiddenDescription_' + id + '" class="hiddenDescription"></div>\
+                               <sup id="previewUrl_' + id + '" class="previewUrl"></sup>\
                        </div>\
                        <div class="clear"></div>\
                        <hr class="previewseparator">';
@@ -72,7 +71,7 @@
                 * @returns {void}
                 */
                var init = function() {
-                       $('#' + selector).bind({
+                       $('#' + id).bind({
                                paste: function () {
                                        setTimeout(function () {
                                                crawlText();
@@ -88,7 +87,7 @@
 
                        // Check if we have already attachment bbcode in the textarea
                        // and add it to the attachment preview.
-                       var content = $('#' + selector).val();
+                       var content = $('#' + id).val();
                        addBBCodeToPreview(content);
                };
 
@@ -98,7 +97,7 @@
                 * @returns {void}
                 */
                var resetPreview = function() {
-                       $('#hasAttachment_' + selector).val(0);
+                       $('#hasAttachment_' + id).val(0);
                        photoNumber = 0;
                        images = "";
                };
                        // If no text is passed to crawlText() we 
                        // take the previous word before the cursor.
                        if (typeof text === 'undefined') {
-                               text = getPrevWord(selector);
+                               text = getPrevWord(id);
                        } else {
                                isExtern = true;
                        }
                                return;
                        }
 
-                       $('#photoNumber_' + selector).val(0);
+                       $('#photoNumber_' + id).val(0);
                        resetPreview();
 
                        processAttachmentTpl(data, 'type-' + data.type);
                 */
                var processAttachmentTpl = function(data) {
                        // Load and add the template if it isn't allready loaded.
-                       if ($('#preview_' + selector).length === 0) {
+                       if ($('#preview_' + id).length === 0) {
                                var tpl = previewTpl.format(
                                        'type-' + data.type,
                                        attachmentTpl,
                                        bin2hex(data.url),
                                        data.type
                                );
-                               $('#' + selector).after(tpl);
+                               $('#' + id).after(tpl);
                        }
 
                        isActive = true;
                                description = defaultDescription;
                        }
 
-                       $('#previewTitle_' + selector).html("\
-                               <span id='previewSpanTitle_" + selector + "' class='previewSpanTitle' >" + escapeHTML(data.title) + "</span>\
-                               <input type='text' name='attachment_title' value='" + escapeHTML(data.title) + "' id='previewInputTitle_" + selector + "' class='previewInputTitle inputPreview' style='display: none;'/>"
+                       $('#previewTitle_' + id).html("\
+                               <span id='previewSpanTitle_" + id + "' class='previewSpanTitle' >" + escapeHTML(data.title) + "</span>\
+                               <input type='text' name='attachment_title' value='" + escapeHTML(data.title) + "' id='previewInputTitle_" + id + "' class='previewInputTitle inputPreview' style='display: none;'/>"
                        );
 
-                       $('#previewDescription_' + selector).html("\
-                               <span id='previewSpanDescription_" + selector + "' class='previewSpanDescription' >" + escapeHTML(description) + "</span>\n\
-                               <textarea id='previewInputDescription_" + selector + "' name='attachment_text' class='previewInputDescription' style='display: none;' class='inputPreview' >" + escapeHTML(data.text) + "</textarea>"
+                       $('#previewDescription_' + id).html("\
+                               <span id='previewSpanDescription_" + id + "' class='previewSpanDescription' >" + escapeHTML(description) + "</span>\n\
+                               <textarea id='previewInputDescription_" + id + "' name='attachment_text' class='previewInputDescription' style='display: none;' class='inputPreview' >" + escapeHTML(data.text) + "</textarea>"
                        );
                };
 
                                var regexpr = "(https?://)([^:^/]*)(:\\d*)?(.*)?";
                                var regResult = url.match(regexpr);
                                var urlHost = regResult[1] + regResult[2];
-                               $('#previewUrl_' + selector).html("<a href='" + url + "'>" + urlHost + "</a>");
+                               $('#previewUrl_' + id).html("<a href='" + url + "'>" + urlHost + "</a>");
                        }
                };
 
                        var imageClass = 'attachment-preview';
        
                        if (Array.isArray(images)) {
-                               $('#previewImages_' + selector).show();
-                               $('#attachmentImageSrc_' + selector).val(bin2hex(images[photoNumber].src));
-                               $('#attachmentImageWidth_' + selector).val(images[photoNumber].width);
-                               $('#attachmentImageHeight_' + selector).val(images[photoNumber].height);
+                               $('#previewImages_' + id).show();
+                               $('#attachmentImageSrc_' + id).val(bin2hex(images[photoNumber].src));
+                               $('#attachmentImageWidth_' + id).val(images[photoNumber].width);
+                               $('#attachmentImageHeight_' + id).val(images[photoNumber].height);
                        } else {
-                               $('#previewImages_' + selector).hide();
+                               $('#previewImages_' + id).hide();
                        }
 
                        images.length = parseInt(images.length);
                                }
 
                                if (i === 0) {
-                                       appendImage += "<img id='imagePreview_" + selector + "_" + i + "' src='" + images[i].src + "' class='" + imageClass + "' ></img>";
+                                       appendImage += "<img id='imagePreview_" + id + "_" + i + "' src='" + images[i].src + "' class='" + imageClass + "' ></img>";
                                } else {
-                                       appendImage += "<img id='imagePreview_" + selector + "_" + i + "' src='" + images[i].src + "' class='" + imageClass + "' style='display: none;'></img>";
+                                       appendImage += "<img id='imagePreview_" + id + "_" + i + "' src='" + images[i].src + "' class='" + imageClass + "' style='display: none;'></img>";
                                }
                        }
 
-                       $('#previewImage_' + selector).html(appendImage + "<div id='whiteImage' style='color: transparent; display:none;'>...</div>");
+                       $('#previewImage_' + id).html(appendImage + "<div id='whiteImage' style='color: transparent; display:none;'>...</div>");
 
                        // More than just one image.
                        if (images.length > 1) {
                                // Enable the the button to change the preview pictures.
-                               $('#previewChangeImg_' + selector).show();
+                               $('#previewChangeImg_' + id).show();
 
                                if (firstPosted === false) {
                                        firstPosted = true;
 
-                                       $('#previewChangeImg_' + selector).unbind('click').click(function (e) {
+                                       $('#previewChangeImg_' + id).unbind('click').click(function (e) {
                                                e.stopPropagation();
                                                if (images.length > 1) {
-                                                       $('#imagePreview_' + selector + '_' + photoNumber).css({
+                                                       $('#imagePreview_' + id + '_' + photoNumber).css({
                                                                'display': 'none'
                                                        });
                                                        photoNumber += 1;
                                                                photoNumber = 0;
                                                        }
 
-                                                       $('#imagePreview_' + selector + '_' + photoNumber).css({
+                                                       $('#imagePreview_' + id + '_' + photoNumber).css({
                                                                'display': 'block'
                                                        });
-                                                       $('#photoNumber_' + selector).val(photoNumber);
-                                                       $('#attachmentImageSrc_' + selector).val(bin2hex(images[photoNumber].src));
-                                                       $('#attachmentImageWidth_' + selector).val(images[photoNumber].width);
-                                                       $('#attachmentImageHeight_' + selector).val(images[photoNumber].height);
+                                                       $('#photoNumber_' + id).val(photoNumber);
+                                                       $('#attachmentImageSrc_' + id).val(bin2hex(images[photoNumber].src));
+                                                       $('#attachmentImageWidth_' + id).val(images[photoNumber].width);
+                                                       $('#attachmentImageHeight_' + id).val(images[photoNumber].height);
                                                }
                                        });
                                }
                 * @returns {void}
                 */
                var processEventListener = function() {
-                       $('#previewSpanTitle_' + selector).unbind('click').click(function (e) {
+                       $('#previewSpanTitle_' + id).unbind('click').click(function (e) {
                                e.stopPropagation();
                                if (blockTitle === false) {
                                        blockTitle = true;
-                                       $('#previewSpanTitle_' + selector).hide();
-                                       $('#previewInputTitle_' + selector).show();
-                                       $('#previewInputTitle_' + selector).val($('#previewInputTitle_' + selector).val());
-                                       $('#previewInputTitle_' + selector).focus().select();
+                                       $('#previewSpanTitle_' + id).hide();
+                                       $('#previewInputTitle_' + id).show();
+                                       $('#previewInputTitle_' + id).val($('#previewInputTitle_' + id).val());
+                                       $('#previewInputTitle_' + id).focus().select();
                                }
                        });
 
-                       $('#previewInputTitle_' + selector).blur(function () {
+                       $('#previewInputTitle_' + id).blur(function () {
                                blockTitle = false;
-                               $('#previewSpanTitle_' + selector).html($('#previewInputTitle_' + selector).val());
-                               $('#previewSpanTitle_' + selector).show();
-                               $('#previewInputTitle_' + selector).hide();
+                               $('#previewSpanTitle_' + id).html($('#previewInputTitle_' + id).val());
+                               $('#previewSpanTitle_' + id).show();
+                               $('#previewInputTitle_' + id).hide();
                        });
 
-                       $('#previewInputTitle_' + selector).keypress(function (e) {
+                       $('#previewInputTitle_' + id).keypress(function (e) {
                                if (e.which === 13) {
                                        blockTitle = false;
-                                       $('#previewSpanTitle_' + selector).html($('#previewInputTitle_' + selector).val());
-                                       $('#previewSpanTitle_' + selector).show();
-                                       $('#previewInputTitle_' + selector).hide();
+                                       $('#previewSpanTitle_' + id).html($('#previewInputTitle_' + id).val());
+                                       $('#previewSpanTitle_' + id).show();
+                                       $('#previewInputTitle_' + id).hide();
                                }
                        });
 
-                       $('#previewSpanDescription_' + selector).unbind('click').click(function (e) {
+                       $('#previewSpanDescription_' + id).unbind('click').click(function (e) {
                                e.stopPropagation();
                                if (blockDescription === false) {
                                        blockDescription = true;
-                                       $('#previewSpanDescription_' + selector).hide();
-                                       $('#previewInputDescription_' + selector).show();
-                                       $('#previewInputDescription_' + selector).val($('#previewInputDescription_' + selector).val());
-                                       $('#previewInputDescription_' + selector).focus().select();
+                                       $('#previewSpanDescription_' + id).hide();
+                                       $('#previewInputDescription_' + id).show();
+                                       $('#previewInputDescription_' + id).val($('#previewInputDescription_' + id).val());
+                                       $('#previewInputDescription_' + id).focus().select();
                                }
                        });
 
-                       $('#previewInputDescription_' + selector).blur(function () {
+                       $('#previewInputDescription_' + id).blur(function () {
                                blockDescription = false;
-                               $('#previewSpanDescription_' + selector).html($('#previewInputDescription_' + selector).val());
-                               $('#previewSpanDescription_' + selector).show();
-                               $('#previewInputDescription_' + selector).hide();
+                               $('#previewSpanDescription_' + id).html($('#previewInputDescription_' + id).val());
+                               $('#previewSpanDescription_' + id).show();
+                               $('#previewInputDescription_' + id).hide();
                        });
 
-                       $('#previewInputDescription_' + selector).keypress(function (e) {
+                       $('#previewInputDescription_' + id).keypress(function (e) {
                                if (e.which === 13) {
                                        blockDescription = false;
-                                       $('#previewSpanDescription_' + selector).html($('#previewInputDescription_' + selector).val());
-                                       $('#previewSpanDescription_' + selector).show();
-                                       $('#previewInputDescription_' + selector).hide();
+                                       $('#previewSpanDescription_' + id).html($('#previewInputDescription_' + id).val());
+                                       $('#previewSpanDescription_' + id).show();
+                                       $('#previewInputDescription_' + id).hide();
                                }
                        });
 
-                       $('#previewSpanTitle_' + selector).mouseover(function () {
-                               $('#previewSpanTitle_' + selector).css({
+                       $('#previewSpanTitle_' + id).mouseover(function () {
+                               $('#previewSpanTitle_' + id).css({
                                        "background-color": "#ff9"
                                });
                        });
 
-                       $('#previewSpanTitle_' + selector).mouseout(function () {
-                               $('#previewSpanTitle_' + selector).css({
+                       $('#previewSpanTitle_' + id).mouseout(function () {
+                               $('#previewSpanTitle_' + id).css({
                                        "background-color": "transparent"
                                });
                        });
 
-                       $('#previewSpanDescription_' + selector).mouseover(function () {
-                               $('#previewSpanDescription_' + selector).css({
+                       $('#previewSpanDescription_' + id).mouseover(function () {
+                               $('#previewSpanDescription_' + id).css({
                                        "background-color": "#ff9"
                                });
                        });
 
-                       $('#previewSpanDescription_' + selector).mouseout(function () {
-                               $('#previewSpanDescription_' + selector).css({
+                       $('#previewSpanDescription_' + id).mouseout(function () {
+                               $('#previewSpanDescription_' + id).css({
                                        "background-color": "transparent"
                                });
                        });
 
-                       $('#closePreview_' + selector).unbind('click').click(function (e) {
+                       $('#closePreview_' + id).unbind('click').click(function (e) {
                                e.stopPropagation();
                                block = false;
                                images = '';
                                isActive = false;
                                firstPosted = false;
-                               $('#preview_' + selector).fadeOut("fast", function () {
-                                       $('#preview_' + selector).remove();
+                               $('#preview_' + id).fadeOut("fast", function () {
+                                       $('#preview_' + id).remove();
                                        $('#profile-rotator').hide();
-                                       $('#' + selector).focus();
+                                       $('#' + id).focus();
                                });
 
                        });
                                reAddAttachment(attachmentData);
                                // Remove the attachment bbcode from the textarea.
                                var content = content.replace(/\[attachment[\s\S]*\[\/attachment]/im, '');
-                               $('#' + selector).val(content);
-                               $('#' + selector).focus();
+                               $('#' + id).val(content);
+                               $('#' + id).focus();
                        }
                };
 
                        }
 
                        if (image !== '') {
-                               var appendImage = "<img id='imagePreview_" + selector + "' src='" + image + "' class='" + imageClass + "' ></img>"
-                               $('#previewImage_' + selector).html(appendImage);
-                               $('#attachmentImageSrc_' + selector).val(bin2hex(image));
+                               var appendImage = "<img id='imagePreview_" + id + "' src='" + image + "' class='" + imageClass + "' ></img>"
+                               $('#previewImage_' + id).html(appendImage);
+                               $('#attachmentImageSrc_' + id).val(bin2hex(image));
 
                                // We need to add the image widht and height when it is 
                                // loaded.
                                $('<img/>' ,{
                                        load : function(){
-                                               $('#attachmentImageWidth_' + selector).val(this.width);
-                                               $('#attachmentImageHeight_' + selector).val(this.height);
+                                               $('#attachmentImageWidth_' + id).val(this.width);
+                                               $('#attachmentImageHeight_' + id).val(this.height);
                                        },
                                        src  : image
                                });
                 * @returns {void}
                 */
                var destroy = function() {
-                       $('#' + selector).unbind();
-                       $('#preview_' + selector).remove();
+                       $('#' + id).unbind();
+                       $('#preview_' + id).remove();
                        binurl;
                        block = false;
                        blockTitle = false;
                        firstPosted = false;
                        isActive = false;
                        isCrawling = false;
-                       selector = "";
+                       id = "";
                };
 
                var trim = function(str) {
index 94644c5dfd2c3467d796b6449f71959cb8e89d6e..37975dd3385b57db1d3692cefe56a5e7738d6a81 100644 (file)
@@ -649,14 +649,16 @@ function doignore(ident) {
        ident = ident.toString();
        $('#like-rotator-' + ident).show();
        $.get('item/ignore/' + ident, function(data) {
-               if (data.match(/1/)) {
-                       $('#ignored-' + ident).addClass('ignored');
-                       $('#ignored-' + ident).removeClass('unignored');
+               if (data === 1) {
+                       $('#ignored-' + ident)
+                               .addClass('ignored')
+                               .removeClass('unignored');
                        $('#ignore-' + ident).addClass('hidden');
                        $('#unignore-' + ident).removeClass('hidden');
                } else {
-                       $('#ignored-' + ident).addClass('unignored');
-                       $('#ignored-' + ident).removeClass('ignored');
+                       $('#ignored-' + ident)
+                               .addClass('unignored')
+                               .removeClass('ignored');
                        $('#ignore-' + ident).removeClass('hidden');
                        $('#unignore-' + ident).addClass('hidden');
                }
@@ -764,11 +766,10 @@ function showHideComments(id) {
 }
 
 function preview_post() {
-       $("#jot-preview").val("1");
        $("#jot-preview-content").show();
        $.post(
                "item",
-               $("#profile-jot-form").serialize(),
+               $("#profile-jot-form").serialize() + '&preview=1',
                function(data) {
                        if (data.preview) {
                                $("#jot-preview-content").html(data.preview);
@@ -778,7 +779,6 @@ function preview_post() {
                },
                "json"
        );
-       $("#jot-preview").val("0");
        return true;
 }
 
index 58a0f483b8eb8a3bc2c0a32021ac566d686ace71..4da7862bb12adac14e7feb62e2c4fce1b843e580 100644 (file)
-
 <div id="acl-wrapper">
-       <input id="acl-search" autocomplete="off">
-       <a id="acl-showall">{{$showall}}</a>
-       <div id="acl-list">
-               <div id="acl-list-content">
+       <div class="panel-group" id="visibility-accordion" role="tablist" aria-multiselectable="true">
+               <div class="panel panel-success">
+                       <label class="panel-heading{{if $visibility != 'public'}} collapsed{{/if}}" id="visibility-public-heading" aria-expanded="{{if $visibility == 'public'}}true{{else}}false{{/if}}">
+                               <input type="radio" name="visibility" id="visibility-public" value="public" tabindex="14" {{if $visibility == 'public'}}checked{{/if}}>
+                               <i class="fa fa-globe"></i> {{$public_title}}
+                       </label>
+                       <fieldset id="visibility-public-panel" class="panel-collapse collapse{{if $visibility == 'public'}} in{{/if}}" role="tabpanel" aria-labelledby="visibility-public-heading" {{if $visibility != 'public'}}disabled{{/if}}>
+                               <div class="panel-body">
+                                       <p>{{$public_desc}}</p>
+                       {{if $for_federation}}
+                               {{if $user_hidewall}}
+                                       <h4>{{$jotnets_summary}}</h4>
+                               {{$jotnets_disabled_label}}
+                               {{elseif $jotnets_fields}}
+                                   {{if $jotnets_fields|count < 3}}
+                                                               <div class="profile-jot-net">
+                                   {{else}}
+                                                               <details class="profile-jot-net">
+                                                               <summary>{{$jotnets_summary}}</summary>
+                                   {{/if}}
+
+                                   {{foreach $jotnets_fields as $jotnets_field}}
+                                       {{if $jotnets_field.type == 'checkbox'}}
+                                           {{include file="field_checkbox.tpl" field=$jotnets_field.field}}
+                                       {{elseif $jotnets_field.type == 'select'}}
+                                           {{include file="field_select.tpl" field=$jotnets_field.field}}
+                                       {{/if}}
+                                   {{/foreach}}
+
+                                   {{if $jotnets_fields|count >= 3}}
+                                                               </details>
+                                   {{else}}
+                                                               </div>
+                                   {{/if}}
+                                   {{/if}}
+                       {{/if}}
+                               </div>
+                       </fieldset>
+               </div>
+               <div class="panel panel-info">
+                       <label class="panel-heading{{if $visibility != 'custom'}} collapsed{{/if}}" id="visibility-custom-heading" aria-expanded="{{if $visibility == 'custom'}}true{{else}}false{{/if}}">
+                               <input type="radio" name="visibility" id="visibility-custom" value="custom" tabindex="15" {{if $visibility == 'custom'}}checked{{/if}}>
+                               <i class="fa fa-lock"></i> {{$custom_title}}
+                       </label>
+                       <fieldset id="visibility-custom-panel" class="panel-collapse collapse{{if $visibility == 'custom'}} in{{/if}}" role="tabpanel" aria-labelledby="visibility-custom-heading" {{if $visibility != 'custom'}}disabled{{/if}}>
+                               <input type="hidden" name="group_allow" value="{{$group_allow}}"/>
+                               <input type="hidden" name="contact_allow" value="{{$contact_allow}}"/>
+                               <input type="hidden" name="group_deny" value="{{$group_deny}}"/>
+                               <input type="hidden" name="contact_deny" value="{{$contact_deny}}"/>
+                               <div class="panel-body">
+                                       <p>{{$custom_desc}}</p>
+
+                                       <div class="form-group">
+                                               <label for="acl_allow">{{$allow_label}}</label>
+                                               <input type="text" class="form-control input-lg" id="acl_allow">
+                                       </div>
+
+                                       <div class="form-group">
+                                               <label for="acl_deny">{{$deny_label}}</label>
+                                               <input type="text" class="form-control input-lg" id="acl_deny">
+                                       </div>
+                               </div>
+                       </fieldset>
                </div>
        </div>
-       <span id="acl-fields"></span>
-</div>
 
-<div class="acl-list-item" rel="acl-template" style="display:none">
-       <img data-src="{0}"><p>{1}</p>
-       <a class='acl-button-show'>{{$show}}</a>
-       <a class='acl-button-hide'>{{$hide}}</a>
-</div>
 
-{{if $networks}}
-<hr style="clear:both"/>
-<div id="profile-jot-email-label">{{$emailcc}}</div><input type="text" name="emailcc" id="profile-jot-email" title="{{$emtitle}}" />
-<div id="profile-jot-email-end"></div>
-
-       {{if $jotnets_fields}}
-               {{if $jotnets_fields|count < 3}}
-<div class="profile-jot-net">
-               {{else}}
-<details class="profile-jot-net">
-       <summary>{{$jotnets_summary}}</summary>
-               {{/if}}
-
-               {{foreach $jotnets_fields as $jotnets_field}}
-                       {{if $jotnets_field.type == 'checkbox'}}
-                               {{include file="field_checkbox.tpl" field=$jotnets_field.field}}
-                       {{elseif $jotnets_field.type == 'select'}}
-                               {{include file="field_select.tpl" field=$jotnets_field.field}}
-                       {{/if}}
-               {{/foreach}}
-
-               {{if $jotnets_fields|count >= 3}}
-</details>
-               {{else}}
-</div>
-               {{/if}}
-       {{/if}}
+{{if $for_federation}}
+       <div class="form-group">
+               <label for="profile-jot-email" id="profile-jot-email-label">{{$emailcc}}</label>
+               <input type="text" name="emailcc" id="profile-jot-email" class="form-control" title="{{$emtitle}}" />
+       </div>
+       <div id="profile-jot-email-end"></div>
 {{/if}}
+</div>
+<script type="text/javascript">
+       $(function() {
+               let $acl_allow_input = $('#acl_allow');
+               let $contact_allow_input = $('[name=contact_allow]');
+               let $group_allow_input = $('[name=group_allow]');
+               let $acl_deny_input = $('#acl_deny');
+               let $contact_deny_input = $('[name=contact_deny]');
+               let $group_deny_input = $('[name=group_deny]');
+               let $visibility_public_panel = $('#visibility-public-panel');
+               let $visibility_custom_panel = $('#visibility-custom-panel');
+               let $visibility_public_radio = $('#visibility-public');
+               let $visibility_custom_radio = $('#visibility-custom');
+
+               // Frio specific
+               if ($.fn.collapse) {
+                       $visibility_public_panel.collapse({parent: '#visibility-accordion', toggle: false});
+                       $visibility_custom_panel.collapse({parent: '#visibility-accordion', toggle: false});
+               }
+
+               $visibility_public_radio.on('change', function (e) {
+                       if ($.fn.collapse) {
+                               $visibility_public_panel.collapse('show');
+                       }
+
+                       $visibility_public_panel.prop('disabled', false);
+                       $visibility_custom_panel.prop('disabled', true);
+
+                       $('.profile-jot-net input[type=checkbox]').each(function() {
+                               // Restores checkbox state if it had been saved
+                               if ($(this).attr('data-checked') !== undefined) {
+                                       $(this).prop('checked', $(this).attr('data-checked') === 'true');
+                               }
+                       });
+                       $('.profile-jot-net input').attr('disabled', false);
+               });
+
+               $visibility_custom_radio.on('change', function(e) {
+                       if ($.fn.collapse) {
+                               $visibility_custom_panel.collapse('show');
+                       }
+
+                       $visibility_public_panel.prop('disabled', true);
+                       $visibility_custom_panel.prop('disabled', false);
+
+                       $('.profile-jot-net input[type=checkbox]').each(function() {
+                               // Saves current checkbox state
+                               $(this)
+                                       .attr('data-checked', $(this).prop('checked'))
+                                       .prop('checked', false);
+                       });
+                       $('.profile-jot-net input').attr('disabled', 'disabled');
+               });
+
+               // Custom visibility tags inputs
+               let acl_groups = new Bloodhound({
+                       local: {{$acl_groups|@json_encode nofilter}},
+                       identify: function(obj) { return obj.id; },
+                       datumTokenizer: Bloodhound.tokenizers.obj.whitespace(['name']),
+                       queryTokenizer: Bloodhound.tokenizers.whitespace,
+               });
+               let acl_contacts = new Bloodhound({
+                       local: {{$acl_contacts|@json_encode nofilter}},
+                       identify: function(obj) { return obj.id; },
+                       datumTokenizer: Bloodhound.tokenizers.obj.whitespace(['name', 'addr']),
+                       queryTokenizer: Bloodhound.tokenizers.whitespace,
+               });
+               let acl = new Bloodhound({
+                       local: {{$acl_list|@json_encode nofilter}},
+                       identify: function(obj) { return obj.id; },
+                       datumTokenizer: Bloodhound.tokenizers.obj.whitespace(['name', 'addr']),
+                       queryTokenizer: Bloodhound.tokenizers.whitespace,
+               });
+               acl.initialize();
+
+               let suggestionTemplate = function (item) {
+                       return '<div><img src="' + item.micro + '" alt="" style="float: left; width: auto; height: 2.8em; margin-right: 0.5em;"> <strong>' + item.name + '</strong><br /><em>' + item.addr + '</em></div>';
+               };
+
+               $acl_allow_input.tagsinput({
+                       confirmKeys: [13, 44],
+                       freeInput: false,
+                       tagClass: function(item) {
+                               switch (item.type) {
+                                       case 'group'   : return 'label label-primary';
+                                       case 'contact'  :
+                                       default:
+                                               return 'label label-info';
+                               }
+                       },
+                       itemValue: 'id',
+                       itemText: 'name',
+                       itemThumb: 'micro',
+                       itemTitle: function(item) {
+                               return item.addr;
+                       },
+                       typeaheadjs: {
+                               name: 'contacts',
+                               displayKey: 'name',
+                               templates: {
+                                       suggestion: suggestionTemplate
+                               },
+                               source: acl.ttAdapter()
+                       }
+               });
+
+               $acl_deny_input
+                       .tagsinput({
+                               confirmKeys: [13, 44],
+                               freeInput: false,
+                               tagClass: function(item) {
+                                       switch (item.type) {
+                                               case 'group'   : return 'label label-primary';
+                                               case 'contact'  :
+                                               default:
+                                                       return 'label label-info';
+                                       }
+                               },
+                               itemValue: 'id',
+                               itemText: 'name',
+                               itemThumb: 'micro',
+                               itemTitle: function(item) {
+                                       return item.addr;
+                               },
+                               typeaheadjs: {
+                                       name: 'contacts',
+                                       displayKey: 'name',
+                                       templates: {
+                                               suggestion: suggestionTemplate
+                                       },
+                                       source: acl.ttAdapter()
+                               }
+                       });
+
+               // Import existing ACL into the tags input fields.
+
+               $group_allow_input.val().split(',').forEach(function (val) {
+                       $acl_allow_input.tagsinput('add', acl_groups.get(val)[0]);
+               });
+               $contact_allow_input.val().split(',').forEach(function (val) {
+                       $acl_allow_input.tagsinput('add', acl_contacts.get(val)[0]);
+               });
+               $group_deny_input.val().split(',').forEach(function (val) {
+                       $acl_deny_input.tagsinput('add', acl_groups.get(val)[0]);
+               });
+               $contact_deny_input.val().split(',').forEach(function (val) {
+                       $acl_deny_input.tagsinput('add', acl_contacts.get(val)[0]);
+               });
+
+               // Anti-duplicate callback + acl fields value generation
+
+               $acl_allow_input.on('itemAdded', function (event) {
+                       // Removes duplicate in the opposite acl box
+                       $acl_deny_input.tagsinput('remove', event.item);
+
+                       // Update the real acl field
+                       $group_allow_input.val('');
+                       $contact_allow_input.val('');
+                       [].forEach.call($acl_allow_input.tagsinput('items'), function (item) {
+                               if (item.type === 'group') {
+                                       $group_allow_input.val($group_allow_input.val() + ',' + item.id);
+                               } else {
+                                       $contact_allow_input.val($contact_allow_input.val() + ',' + item.id);
+                               }
+                       });
+               });
+
+               $acl_deny_input.on('itemAdded', function (event) {
+                       // Removes duplicate in the opposite acl box
+                       $acl_allow_input.tagsinput('remove', event.item);
 
-<script>
-$(document).ready(function() {
-       if(typeof acl=="undefined"){
-               acl = new ACL(
-                       baseurl + '/search/acl',
-                       [ {{$allowcid nofilter}},{{$allowgid nofilter}},{{$denycid nofilter}},{{$denygid nofilter}} ],
-                       {{$features.aclautomention}},
-                       {{if $APP->is_mobile}}true{{else}}false{{/if}}
-               );
-       }
-});
+                       // Update the real acl field
+                       $group_deny_input.val('');
+                       $contact_deny_input.val('');
+                       [].forEach.call($acl_deny_input.tagsinput('items'), function (item) {
+                               if (item.type === 'group') {
+                                       $group_deny_input.val($group_allow_input.val() + ',' + item.id);
+                               } else {
+                                       $contact_deny_input.val($contact_allow_input.val() + ',' + item.id);
+                               }
+                       });
+               });
+       });
 </script>
index 3d11f1ab8634b9550ef346fd0f72d110f46dc1bd..6e3f741adaca04bd9dcd2a3f76960a243db3e2f5 100644 (file)
@@ -42,7 +42,6 @@
 <script type="text/javascript" src="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.full.min.js"></script>
 <script type="text/javascript" src="view/asset/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js" ></script>
 <script type="text/javascript" src="view/asset/imagesloaded/imagesloaded.pkgd.min.js"></script>
-<script type="text/javascript" src="view/js/acl.js" ></script>
 <script type="text/javascript" src="view/asset/base64/base64.min.js" ></script>
 <script type="text/javascript" src="view/asset/dompurify/dist/purify.min.js"></script>
 <script type="text/javascript" src="view/js/main.js" ></script>
diff --git a/view/templates/item/compose-footer.tpl b/view/templates/item/compose-footer.tpl
deleted file mode 100644 (file)
index 7e18d18..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-<script type="text/javascript">
-       function updateLocationButtonDisplay(location_button, location_input)
-       {
-               location_button.classList.remove('btn-primary');
-               if (location_input.value) {
-                       location_button.disabled = false;
-                       location_button.classList.add('btn-primary');
-                       location_button.title = location_button.dataset.titleClear;
-               } else if (!"geolocation" in navigator) {
-                       location_button.disabled = true;
-                       location_button.title = location_button.dataset.titleUnavailable;
-               } else if (location_button.disabled) {
-                       location_button.title = location_button.dataset.titleDisabled;
-               } else {
-                       location_button.title = location_button.dataset.titleSet;
-               }
-       }
-
-       $(function() {
-               // Jot attachment live preview.
-               let $textarea = $('#comment-edit-text-0');
-               $textarea.linkPreview();
-               $textarea.keyup(function(){
-                       var textlen = $(this).val().length;
-                       $('#character-counter').text(textlen);
-               });
-               $textarea.editor_autocomplete(baseurl + '/search/acl');
-               $textarea.bbco_autocomplete('bbcode');
-
-               let $acl_allow_input = $('#acl_allow');
-               let $group_allow_input = $('[name=group_allow]');
-               let $contact_allow_input = $('[name=contact_allow]');
-               let $acl_deny_input = $('#acl_deny');
-               let $group_deny_input = $('[name=group_deny]');
-               let $contact_deny_input = $('[name=contact_deny]');
-
-               // Visibility accordion
-
-               // Prevents open panel to collapse
-               // @see https://stackoverflow.com/a/43593116
-               $('[data-toggle="collapse"]').click(function(e) {
-                       target = $(this).attr('href');
-                       if ($(target).hasClass('in')) {
-                               e.preventDefault(); // to stop the page jump to the anchor target.
-                               e.stopPropagation()
-                       }
-               });
-               // Accessibility: enable space and enter to open a panel when focused
-               $('body').on('keyup', '[data-toggle="collapse"]:focus', function (e) {
-                       if (e.key === ' ' || e.key === 'Enter') {
-                               $(this).click();
-                               e.preventDefault();
-                               e.stopPropagation();
-                       }
-               });
-
-               $('#visibility-public-panel').on('show.bs.collapse', function() {
-                       $('#visibility-public').prop('checked', true);
-                       $group_allow_input.prop('disabled', true);
-                       $contact_allow_input.prop('disabled', true);
-                       $group_deny_input.prop('disabled', true);
-                       $contact_deny_input.prop('disabled', true);
-
-                       $('.profile-jot-net input[type=checkbox]').each(function() {
-                               // Restores checkbox state if it had been saved
-                               if ($(this).attr('data-checked') !== undefined) {
-                                       $(this).prop('checked', $(this).attr('data-checked') === 'true');
-                               }
-                       });
-                       $('.profile-jot-net input').attr('disabled', false);
-               });
-
-               $('#visibility-custom-panel').on('show.bs.collapse', function() {
-                       $('#visibility-custom').prop('checked', true);
-                       $group_allow_input.prop('disabled', false);
-                       $contact_allow_input.prop('disabled', false);
-                       $group_deny_input.prop('disabled', false);
-                       $contact_deny_input.prop('disabled', false);
-
-                       $('.profile-jot-net input[type=checkbox]').each(function() {
-                               // Saves current checkbox state
-                               $(this)
-                                       .attr('data-checked', $(this).prop('checked'))
-                                       .prop('checked', false);
-                       });
-                       $('.profile-jot-net input').attr('disabled', 'disabled');
-               });
-
-               if (document.querySelector('input[name="visibility"]:checked').value === 'custom') {
-                       $('#visibility-custom-panel').collapse({parent: '#visibility-accordion'});
-               }
-
-               // Custom visibility tags inputs
-
-               let acl_groups = new Bloodhound({
-                       local: {{$acl_groups|@json_encode nofilter}},
-                       identify: function(obj) { return obj.id; },
-                       datumTokenizer: Bloodhound.tokenizers.obj.whitespace(['name']),
-                       queryTokenizer: Bloodhound.tokenizers.whitespace,
-               });
-               let acl_contacts = new Bloodhound({
-                       local: {{$acl_contacts|@json_encode nofilter}},
-                       identify: function(obj) { return obj.id; },
-                       datumTokenizer: Bloodhound.tokenizers.obj.whitespace(['name', 'addr']),
-                       queryTokenizer: Bloodhound.tokenizers.whitespace,
-               });
-               let acl = new Bloodhound({
-                       local: {{$acl|@json_encode nofilter}},
-                       identify: function(obj) { return obj.id; },
-                       datumTokenizer: Bloodhound.tokenizers.obj.whitespace(['name', 'addr']),
-                       queryTokenizer: Bloodhound.tokenizers.whitespace,
-               });
-               acl.initialize();
-
-               let suggestionTemplate = function (item) {
-                       return '<div><img src="' + item.micro + '" alt="" style="float: left; width: auto; height: 2.8em; margin-right: 0.5em;"> <strong>' + item.name + '</strong><br /><em>' + item.addr + '</em></div>';
-               };
-
-               $acl_allow_input.tagsinput({
-                       confirmKeys: [13, 44],
-                       freeInput: false,
-                       tagClass: function(item) {
-                               switch (item.type) {
-                                       case 'group'   : return 'label label-primary';
-                                       case 'contact'  :
-                                       default:
-                                               return 'label label-info';
-                               }
-                       },
-                       itemValue: 'id',
-                       itemText: 'name',
-                       itemThumb: 'micro',
-                       itemTitle: function(item) {
-                               return item.addr;
-                       },
-                       typeaheadjs: {
-                               name: 'contacts',
-                               displayKey: 'name',
-                               templates: {
-                                       suggestion: suggestionTemplate
-                               },
-                               source: acl.ttAdapter()
-                       }
-               });
-
-               $acl_deny_input
-               .tagsinput({
-                       confirmKeys: [13, 44],
-                       freeInput: false,
-                       tagClass: function(item) {
-                               switch (item.type) {
-                                       case 'group'   : return 'label label-primary';
-                                       case 'contact'  :
-                                       default:
-                                               return 'label label-info';
-                               }
-                       },
-                       itemValue: 'id',
-                       itemText: 'name',
-                       itemThumb: 'micro',
-                       itemTitle: function(item) {
-                               return item.addr;
-                       },
-                       typeaheadjs: {
-                               name: 'contacts',
-                               displayKey: 'name',
-                               templates: {
-                                       suggestion: suggestionTemplate
-                               },
-                               source: acl.ttAdapter()
-                       }
-               });
-
-               // Import existing ACL into the tags input fields.
-
-               $group_allow_input.val().split(',').forEach(function (val) {
-                       $acl_allow_input.tagsinput('add', acl_groups.get(val)[0]);
-               });
-               $contact_allow_input.val().split(',').forEach(function (val) {
-                       $acl_allow_input.tagsinput('add', acl_contacts.get(val)[0]);
-               });
-               $group_deny_input.val().split(',').forEach(function (val) {
-                       $acl_deny_input.tagsinput('add', acl_groups.get(val)[0]);
-               });
-               $contact_deny_input.val().split(',').forEach(function (val) {
-                       $acl_deny_input.tagsinput('add', acl_contacts.get(val)[0]);
-               });
-
-               // Anti-duplicate callback + acl fields value generation
-
-               $acl_allow_input.on('itemAdded', function (event) {
-                       // Removes duplicate in the opposite acl box
-                       $acl_deny_input.tagsinput('remove', event.item);
-
-                       // Update the real acl field
-                       $group_allow_input.val('');
-                       $contact_allow_input.val('');
-                       [].forEach.call($acl_allow_input.tagsinput('items'), function (item) {
-                               if (item.type === 'group') {
-                                       $group_allow_input.val($group_allow_input.val() + '<' + item.id + '>');
-                               } else {
-                                       $contact_allow_input.val($contact_allow_input.val() + '<' + item.id + '>');
-                               }
-                       });
-               });
-
-               $acl_deny_input.on('itemAdded', function (event) {
-                       // Removes duplicate in the opposite acl box
-                       $acl_allow_input.tagsinput('remove', event.item);
-
-                       // Update the real acl field
-                       $group_deny_input.val('');
-                       $contact_deny_input.val('');
-                       [].forEach.call($acl_deny_input.tagsinput('items'), function (item) {
-                               if (item.type === 'group') {
-                                       $group_deny_input.val($group_allow_input.val() + '<' + item.id + '>');
-                               } else {
-                                       $contact_deny_input.val($contact_allow_input.val() + '<' + item.id + '>');
-                               }
-                       });
-               });
-
-               let location_button = document.getElementById('profile-location');
-               let location_input = document.getElementById('jot-location');
-
-               updateLocationButtonDisplay(location_button, location_input);
-
-               location_input.addEventListener('change', function () {
-                       updateLocationButtonDisplay(location_button, location_input);
-               });
-               location_input.addEventListener('keyup', function () {
-                       updateLocationButtonDisplay(location_button, location_input);
-               });
-
-               location_button.addEventListener('click', function() {
-                       if (location_input.value) {
-                               location_input.value = '';
-                               updateLocationButtonDisplay(location_button, location_input);
-                       } else if ("geolocation" in navigator) {
-                               navigator.geolocation.getCurrentPosition(function(position) {
-                                       location_input.value = position.coords.latitude + ', ' + position.coords.longitude;
-                                       updateLocationButtonDisplay(location_button, location_input);
-                               }, function (error) {
-                                       location_button.disabled = true;
-                                       updateLocationButtonDisplay(location_button, location_input);
-                               });
-                       }
-               });
-       })
-</script>
index d18b1a2d36af1aa07ee09193ea7e6ee395d59ad0..8b7414fd6780694c4338786aa687b2789a36d87d 100644 (file)
 
                        <div id="comment-edit-preview-{{$id}}" class="comment-edit-preview" style="display:none;"></div>
 
-                       <input type="hidden" name="group_allow" value="{{$group_allow}}" {{if $visibility == 'public'}}disabled{{/if}}/>
-                       <input type="hidden" name="contact_allow" value="{{$contact_allow}}" {{if $visibility == 'public'}}disabled{{/if}}/>
-                       <input type="hidden" name="group_deny" value="{{$group_deny}}" {{if $visibility == 'public'}}disabled{{/if}}/>
-                       <input type="hidden" name="contact_deny" value="{{$contact_deny}}" {{if $visibility == 'public'}}disabled{{/if}}/>
 {{if $type == 'post'}}
-                       <h3>Visibility</h3>
-                       <div class="panel-group" id="visibility-accordion" role="tablist" aria-multiselectable="true">
-                               <div class="panel panel-success">
-                                       <div class="panel-heading" id="visibility-public-heading" role="button" data-toggle="collapse" data-parent="#visibility-accordion" href="#visibility-public-panel" aria-expanded="true" aria-controls="visibility-public-panel" tabindex="14">
-                                               <label>
-                                                       <input type="radio" name="visibility" id="visibility-public" value="public" {{if $visibility == 'public'}}checked{{/if}} style="display:none">
-                                                       <i class="fa fa-globe"></i> {{$public_title}}
-                                               </label>
-                                       </div>
-                                       <div id="visibility-public-panel" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="visibility-public-heading">
-                                               <div class="panel-body">
-                                                       <p>{{$public_desc}}</p>
-                    {{if $doesFederate && $jotnets_fields}}
-                        {{if $jotnets_fields|count < 3}}
-                                                       <div class="profile-jot-net">
-                        {{else}}
-                                                       <details class="profile-jot-net">
-                                                       <summary>{{$jotnets_summary}}</summary>
-                        {{/if}}
+                       <h3>{{$visibility_title}}</h3>
+                       {{$acl_selector nofilter}}
 
-                        {{foreach $jotnets_fields as $jotnets_field}}
-                            {{if $jotnets_field.type == 'checkbox'}}
-                                {{include file="field_checkbox.tpl" field=$jotnets_field.field}}
-                            {{elseif $jotnets_field.type == 'select'}}
-                                {{include file="field_select.tpl" field=$jotnets_field.field}}
-                            {{/if}}
-                        {{/foreach}}
-
-                        {{if $jotnets_fields|count >= 3}}
-                                                       </details>
-                        {{else}}
-                                                       </div>
-                        {{/if}}
-                    {{/if}}
-                                               </div>
-                                       </div>
-                               </div>
-                               <div class="panel panel-info">
-                                       <div class="panel-heading collapsed" id="visibility-custom-heading" role="button" data-toggle="collapse" data-parent="#visibility-accordion" href="#visibility-custom-panel" aria-expanded="true" aria-controls="visibility-custom-panel" tabindex="15">
-                                               <label>
-                                                       <input type="radio" name="visibility" id="visibility-custom" value="custom" {{if $visibility == 'custom'}}checked{{/if}} style="display:none">
-                                                       <i class="fa fa-lock"></i> {{$custom_title}}
-                                               </label>
-                                       </div>
-                                       <div id="visibility-custom-panel" class="panel-collapse collapse" role="tabpanel" aria-labelledby="visibility-custom-heading">
-                                               <div class="panel-body">
-                                                       <p>{{$custom_desc}}</p>
-
-                                                       <div class="form-group">
-                                                               <label for="acl_allow">Deliver to:</label>
-                                                               <input type="text" class="form-control input-lg" id="acl_allow">
-                                                       </div>
-
-                                                       <div class="form-group">
-                                                               <label for="acl_deny">Except to:</label>
-                                                               <input type="text" class="form-control input-lg" id="acl_deny">
-                                                       </div>
-                                               </div>
-                                       </div>
-                               </div>
-                       </div>
-        {{if $doesFederate}}
-                       <div class="form-group">
-                               <label for="profile-jot-email" id="profile-jot-email-label">{{$emailcc}}</label>
-                               <input type="text" name="emailcc" id="profile-jot-email" class="form-control" title="{{$emtitle}}" />
-                       </div>
-                       <div id="profile-jot-email-end"></div>
-               {{/if}}
                        <div class="jotplugins">
                                {{$jotplugins nofilter}}
                        </div>
+{{else}}
+                       <input type="hidden" name="group_allow" value="{{$group_allow}}"/>
+                       <input type="hidden" name="contact_allow" value="{{$contact_allow}}"/>
+                       <input type="hidden" name="group_deny" value="{{$group_deny}}"/>
+                       <input type="hidden" name="contact_deny" value="{{$contact_deny}}"/>
 {{/if}}
                </form>
        </div>
index 60e2d9c456f53eeb2f32fd431c277c8ca6bcca4a..dc021a619bc2022876192927c2bbd6c7485048ad 100644 (file)
@@ -126,18 +126,13 @@ input#dfrn-url {
        border: 1px solid #cccccc; 
 }
 
-.acl-list-item p, #profile-jot-email-label, div#jot-preview-content, div.profile-jot-net {
+#profile-jot-email-label, div#jot-preview-content, div.profile-jot-net {
         color: #eec;
 }
 #fancybox-content{
   background:#444;
 }
 
-input#acl-search {
-        background-color: #aaa;
-}
-
-
 .notify-seen {
   background:#111;
 }
index bb5a25490e8078a8ab4127571ad37aea3d444ffd..eceaed1247e49d596df0aee4e8b9235ff0325a75 100644 (file)
@@ -1821,97 +1821,14 @@ blockquote.shared_content {
        margin-bottom: 15px;
 }
 
-
 #acl-wrapper {
        width: 690px;
        float:left;
 }
-#acl-search {
-       float:right;
-       background: #ffffff url("../../../images/search_18.png") no-repeat right center;
-       padding-right:20px;
-}
-#acl-showall {
-       float: left;
-       display: block;
-       width: auto;
-       height: 18px;
-       background-color: #cccccc;
-       background-image: url("../../../images/show_all_off.png");
-       background-position: 7px 7px;
-       background-repeat: no-repeat;
-       padding: 7px 5px 0px 30px;
-       -webkit-border-radius: 5px ;
-       -moz-border-radius: 5px;
-       border-radius: 5px;
-       color: #999999;
-}
-#acl-showall.selected {
-       color: #000000;
-       background-color: #ff9900;
-       background-image: url("../../../images/show_all_on.png");
-}
-
-#acl-list {
-       height: 210px;
-       border: 1px solid #cccccc;
-       clear: both;
-       margin-top: 30px;
-       overflow: auto;
-}
-#acl-list-content {
-
-}
-.acl-list-item {
-       display: block;
-       width: 150px;
-       height: 30px;
-       border: 1px solid #cccccc;
-       margin: 5px;
-       float: left;
-}
-.acl-list-item img{
-       width:22px;
-       height: 22px;
-       float: left;
-       margin: 4px;
-}
-.acl-list-item p { height: 12px; font-size: 10px; margin: 0px; padding: 2px 0px 1px; overflow: hidden;}
-.acl-list-item a {
-       font-size: 8px;
-       display: block;
-       width: 40px;
-       height: 10px;
-       float: left;
-       color: #999999;
-       background-color: #cccccc;
-       background-position: 3px 3px;
-       background-repeat: no-repeat;
-       margin-right: 5px;
-       -webkit-border-radius: 2px ;
-       -moz-border-radius: 2px;
-       border-radius: 2px;
-       padding-left: 15px;
-}
 #acl-wrapper a:hover {
        text-decoration: none;
        color:#000000;
 }
-.acl-button-show { background-image: url("../../../images/show_off.png"); }
-.acl-button-hide { background-image: url("../../../images/hide_off.png"); }
-
-.acl-button-show.selected {
-       color: #000000;
-       background-color: #9ade00;
-       background-image: url("../../../images/show_on.png");
-}
-.acl-button-hide.selected {
-       color: #000000;
-       background-color: #ff4141;
-       background-image: url("../../../images/hide_on.png");
-}
-.acl-list-item.groupshow { border-color: #9ade00; }
-.acl-list-item.grouphide { border-color: #ff4141; }
 /** /acl **/
 
 
index b0458d513c432d104e581111ec15fc2f88ded740..c8dfdc1441606cde65b315ece57504a2e94fd277 100644 (file)
@@ -1457,82 +1457,6 @@ textarea.comment-edit-text:focus + .comment-edit-form .preview {
     overflow-y: overlay;
 }
 /* ACL */
-/*#jot-modal-body {
-    height: auto;
-    max-height: calc(100vh - 130px);
-    overflow-y: hidden;
-}*/
-#acl-search {
-    /*margin-top: 20px;*/
-    /*padding: 8px;*/
-    /*border: 1px solid #ccc;*/
-    width: 100%;
-}
-#acl-list {
-    display: block;
-    border: 1px solid #ccc;
-    clear: both;
-    min-height: 62px;
-    margin-top: 20px;
-    padding: 10px 10px 0px 0px;
-    -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
-    border-radius: 4px;
-    overflow-y: auto;
-}
-#acl-list-content {
-    overflow-y: hidden;
-    height: auto !important;
-}
-.acl-list-item {
-    width: 48%;
-    width: calc(50% - 10px);
-    border: 1px solid #ccc;
-    margin: 0px 0px 10px 10px;
-    padding: 5px;
-    float: left;
-    -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
-    border-radius: 4px;
-}
-.acl-list-item img {
-    width: 40px;
-    height: 40px;
-    float: left;
-    margin-right: 5px;
-    -webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
-    border-radius: 4px;
-}
-.acl-list-item p {
-    margin: 0px;
-    white-space: nowrap;
-    overflow: hidden;
-    text-overflow: ellipsis;
-}
-.acl-list-item.groupshow {
-    background-color: #8DB255
-}
-.acl-list-item.grouphide {
-    background-color: #E68364;
-}
-.acl-button-show, .acl-button-hide {
-    float: right;
-    margin-left: 5px;
-}
-#acl-showall.selected {
-    background-color: #4CAF50;
-    color: #fff;
-}
-.acl-button-show.selected {
-    background-color: #4CAF50;
-    color: #fff;
-}
-.acl-button-hide.selected {
-    background-color: #F44336;
-    color: #fff;
-}
-
 .fa.lock:before {
     font-family: ForkAwesome;
     content: "\f023";
@@ -1542,6 +1466,12 @@ textarea.comment-edit-text:focus + .comment-edit-form .preview {
     content: "\f09c";
 }
 
+#acl-wrapper label.panel-heading {
+       display: block;
+       margin-bottom: 0;
+       cursor: pointer;
+}
+
 /* Filebrowser */
 .fbrowser .breadcrumb {
     margin-bottom: 0px;
@@ -2944,15 +2874,23 @@ ul li:hover .contact-wrapper .contact-action-link:hover {
 .section-subtitle-wrapper {
     padding: 1px 10px;
 }
-.panel .section-subtitle-wrapper a.accordion-toggle:before {
+details.profile-jot-net[open] summary:before, .panel .section-subtitle-wrapper a.accordion-toggle:before {
     font-family: ForkAwesome;
     content: "\f0d7";
     padding-right: 5px;
 }
-.panel .section-subtitle-wrapper a.accordion-toggle.collapsed:before {
+details.profile-jot-net summary:before, .panel .section-subtitle-wrapper a.accordion-toggle.collapsed:before {
     font-family: ForkAwesome;
     content: "\f0da";
 }
+details.profile-jot-net summary:before {
+    padding-right: 5px;
+    padding-left: 3px;
+}
+details.profile-jot-net[open] summary:before {
+    padding-right: 5px;
+    padding-left: 0px;
+}
 #settings-nick-wrapper {
     margin-bottom: 20px;
 }
diff --git a/view/theme/frio/frameworks/friendica-tagsinput/LICENSE b/view/theme/frio/frameworks/friendica-tagsinput/LICENSE
deleted file mode 100644 (file)
index 58bc985..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2013 Tim Schlechter
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput-typeahead.css b/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput-typeahead.css
deleted file mode 100644 (file)
index 8cec654..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * friendica-tagsinput v0.8.0
- * 
- */
-
-.twitter-typeahead .tt-query,
-.twitter-typeahead .tt-hint {
-    margin-bottom: 0;
-}
-
-.twitter-typeahead .tt-hint
-{
-    display: none;
-}
-
-.tt-menu {
-    position: absolute;
-    top: 100%;
-    left: 0;
-    z-index: 1000;
-    display: none;
-    float: left;
-    min-width: 160px;
-    padding: 5px 0;
-    margin: 2px 0 0;
-    list-style: none;
-    font-size: 14px;
-    background-color: #ffffff;
-    border: 1px solid #cccccc;
-    border: 1px solid rgba(0, 0, 0, 0.15);
-    border-radius: 4px;
-    -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
-    box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
-    background-clip: padding-box;
-    cursor: pointer;
-}
-
-.tt-suggestion {
-    display: block;
-    padding: 3px 20px;
-    clear: both;
-    font-weight: normal;
-    line-height: 1.428571429;
-    color: #333333;
-    white-space: nowrap;
-}
-
-.tt-suggestion:hover,
-.tt-suggestion:focus {
-    color: #ffffff;
-    text-decoration: none;
-    outline: 0;
-    background-color: #428bca;
-}
diff --git a/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.css b/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.css
deleted file mode 100644 (file)
index f2e1197..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * friendica-tagsinput v0.8.0
- * 
- */
-
-.friendica-tagsinput {
-  background-color: #fff;
-  border: 1px solid #ccc;
-  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-  display: inline-block;
-  padding: 4px 6px;
-  color: #555;
-  vertical-align: middle;
-  border-radius: 4px;
-  max-width: 100%;
-  line-height: 22px;
-  cursor: text;
-  height: auto;
-}
-.friendica-tagsinput.input-lg {
-  line-height: 27px;
-}
-.friendica-tagsinput input {
-  border: none;
-  box-shadow: none;
-  outline: none;
-  background-color: transparent;
-  padding: 0 6px;
-  margin: 0;
-  width: auto;
-  max-width: inherit;
-}
-.friendica-tagsinput.form-control input::-moz-placeholder {
-  color: #777;
-  opacity: 1;
-}
-.friendica-tagsinput.form-control input:-ms-input-placeholder {
-  color: #777;
-}
-.friendica-tagsinput.form-control input::-webkit-input-placeholder {
-  color: #777;
-}
-.friendica-tagsinput input:focus {
-  border: none;
-  box-shadow: none;
-}
-.friendica-tagsinput .tag {
-  margin: 0 2px 2px 0;
-  color: white;
-  font-weight: normal;
-}
-.friendica-tagsinput .tag img {
-  width: auto;
-  height: 1.5em;
-  vertical-align: text-top;
-  margin-right: 8px;
-}
-.friendica-tagsinput .tag [data-role="remove"] {
-  margin-left: 8px;
-  cursor: pointer;
-}
-.friendica-tagsinput .tag [data-role="remove"]:after {
-  content: "x";
-  padding: 0px 2px;
-  font-weight: bold;
-}
-.friendica-tagsinput .tag [data-role="remove"]:hover {
-  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-.friendica-tagsinput .tag [data-role="remove"]:hover:active {
-  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
-}
diff --git a/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.js b/view/theme/frio/frameworks/friendica-tagsinput/friendica-tagsinput.js
deleted file mode 100644 (file)
index af722d7..0000000
+++ /dev/null
@@ -1,695 +0,0 @@
-/*
- * friendica-tagsinput v0.8.0
- * Based on bootstrap-tagsinput v0.8.0
- *
- * Adds:
- * - optional thumbnail
- * - copying source input element class to the pseudo-input element
- *
- */
-
-(function ($) {
-  "use strict";
-
-  var defaultOptions = {
-    tagClass: function(item) {
-      return 'label label-info';
-    },
-    focusClass: 'focus',
-    itemValue: function(item) {
-      return item ? item.toString() : item;
-    },
-    itemText: function(item) {
-      return this.itemValue(item);
-    },
-    itemTitle: function(item) {
-      return null;
-    },
-    itemThumb: function(item) {
-      return null;
-    },
-    freeInput: true,
-    addOnBlur: true,
-    maxTags: undefined,
-    maxChars: undefined,
-    confirmKeys: [13, 44],
-    delimiter: ',',
-    delimiterRegex: null,
-    cancelConfirmKeysOnEmpty: false,
-    onTagExists: function(item, $tag) {
-      $tag.hide().fadeIn();
-    },
-    trimValue: false,
-    allowDuplicates: false,
-    triggerChange: true
-  };
-
-  /**
-   * Constructor function
-   */
-  function TagsInput(element, options) {
-    this.isInit = true;
-    this.itemsArray = [];
-
-    this.$element = $(element);
-    this.$element.hide();
-
-    this.isSelect = (element.tagName === 'SELECT');
-    this.multiple = (this.isSelect && element.hasAttribute('multiple'));
-    this.objectItems = options && options.itemValue;
-    this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
-    this.inputSize = Math.max(1, this.placeholderText.length);
-
-    this.$container = $('<div class="friendica-tagsinput"></div>');
-    this.$container.addClass(this.$element.attr('class'));
-    this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
-
-    this.$element.before(this.$container);
-
-    this.build(options);
-    this.isInit = false;
-  }
-
-  TagsInput.prototype = {
-    constructor: TagsInput,
-
-    /**
-     * Adds the given item as a new tag. Pass true to dontPushVal to prevent
-     * updating the elements val()
-     */
-    add: function(item, dontPushVal, options) {
-      let self = this;
-
-      if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags)
-        return;
-
-      // Ignore falsey values, except false
-      if (item !== false && !item)
-        return;
-
-      // Trim value
-      if (typeof item === "string" && self.options.trimValue) {
-        item = $.trim(item);
-      }
-
-      // Throw an error when trying to add an object while the itemValue option was not set
-      if (typeof item === "object" && !self.objectItems)
-        throw("Can't add objects when itemValue option is not set");
-
-      // Ignore strings only containg whitespace
-      if (item.toString().match(/^\s*$/))
-        return;
-
-      // If SELECT but not multiple, remove current tag
-      if (self.isSelect && !self.multiple && self.itemsArray.length > 0)
-        self.remove(self.itemsArray[0]);
-
-      if (typeof item === "string" && this.$element[0].tagName === 'INPUT') {
-        var delimiter = (self.options.delimiterRegex) ? self.options.delimiterRegex : self.options.delimiter;
-        var items = item.split(delimiter);
-        if (items.length > 1) {
-          for (var i = 0; i < items.length; i++) {
-            this.add(items[i], true);
-          }
-
-          if (!dontPushVal)
-            self.pushVal(self.options.triggerChange);
-          return;
-        }
-      }
-
-      var itemValue = self.options.itemValue(item),
-          itemText = self.options.itemText(item),
-          tagClass = self.options.tagClass(item),
-          itemTitle = self.options.itemTitle(item),
-          itemThumb = self.options.itemThumb(item);
-
-      // Ignore items allready added
-      var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0];
-      if (existing && !self.options.allowDuplicates) {
-        // Invoke onTagExists
-        if (self.options.onTagExists) {
-          var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; });
-          self.options.onTagExists(item, $existingTag);
-        }
-        return;
-      }
-
-      // if length greater than limit
-      if (self.items().toString().length + item.length + 1 > self.options.maxInputLength)
-        return;
-
-      // raise beforeItemAdd arg
-      var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options});
-      self.$element.trigger(beforeItemAddEvent);
-      if (beforeItemAddEvent.cancel)
-        return;
-
-      // register item in internal array and map
-      self.itemsArray.push(item);
-
-      // add a tag element
-      var $tag = $('<span class="tag ' + htmlEncode(tagClass) + (itemTitle !== null ? ('" title="' + itemTitle) : '') + '">' +
-          (itemThumb !== null ? '<img src="' + itemThumb + '" alt="">' : '') +
-          htmlEncode(itemText) + '<span data-role="remove"></span>' +
-          '</span>');
-      $tag.data('item', item);
-      self.findInputWrapper().before($tag);
-      $tag.after(' ');
-
-      // Check to see if the tag exists in its raw or uri-encoded form
-      var optionExists = (
-          $('option[value="' + encodeURIComponent(itemValue) + '"]', self.$element).length ||
-          $('option[value="' + htmlEncode(itemValue) + '"]', self.$element).length
-      );
-
-      // add <option /> if item represents a value not present in one of the <select />'s options
-      if (self.isSelect && !optionExists) {
-        var $option = $('<option selected>' + htmlEncode(itemText) + '</option>');
-        $option.data('item', item);
-        $option.attr('value', itemValue);
-        self.$element.append($option);
-      }
-
-      if (!dontPushVal)
-        self.pushVal(self.options.triggerChange);
-
-      // Add class when reached maxTags
-      if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength)
-        self.$container.addClass('friendica-tagsinput-max');
-
-      // If using typeahead, once the tag has been added, clear the typeahead value so it does not stick around in the input.
-      if ($('.typeahead, .twitter-typeahead', self.$container).length) {
-        self.$input.typeahead('val', '');
-      }
-
-      if (this.isInit) {
-        self.$element.trigger($.Event('itemAddedOnInit', { item: item, options: options }));
-      } else {
-        self.$element.trigger($.Event('itemAdded', { item: item, options: options }));
-      }
-    },
-
-    /**
-     * Removes the given item. Pass true to dontPushVal to prevent updating the
-     * elements val()
-     */
-    remove: function(item, dontPushVal, options) {
-      var self = this;
-
-      if (self.objectItems) {
-        if (typeof item === "object")
-          item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) ==  self.options.itemValue(item); } );
-        else
-          item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) ==  item; } );
-
-        item = item[item.length-1];
-      }
-
-      if (item) {
-        var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options });
-        self.$element.trigger(beforeItemRemoveEvent);
-        if (beforeItemRemoveEvent.cancel)
-          return;
-
-        $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove();
-        $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove();
-        if($.inArray(item, self.itemsArray) !== -1)
-          self.itemsArray.splice($.inArray(item, self.itemsArray), 1);
-      }
-
-      if (!dontPushVal)
-        self.pushVal(self.options.triggerChange);
-
-      // Remove class when reached maxTags
-      if (self.options.maxTags > self.itemsArray.length)
-        self.$container.removeClass('friendica-tagsinput-max');
-
-      self.$element.trigger($.Event('itemRemoved',  { item: item, options: options }));
-    },
-
-    /**
-     * Removes all items
-     */
-    removeAll: function() {
-      var self = this;
-
-      $('.tag', self.$container).remove();
-      $('option', self.$element).remove();
-
-      while(self.itemsArray.length > 0)
-        self.itemsArray.pop();
-
-      self.pushVal(self.options.triggerChange);
-    },
-
-    /**
-     * Refreshes the tags so they match the text/value of their corresponding
-     * item.
-     */
-    refresh: function() {
-      var self = this;
-      $('.tag', self.$container).each(function() {
-        var $tag = $(this),
-            item = $tag.data('item'),
-            itemValue = self.options.itemValue(item),
-            itemText = self.options.itemText(item),
-            tagClass = self.options.tagClass(item);
-
-          // Update tag's class and inner text
-          $tag.attr('class', null);
-          $tag.addClass('tag ' + htmlEncode(tagClass));
-          $tag.contents().filter(function() {
-            return this.nodeType == 3;
-          })[0].nodeValue = htmlEncode(itemText);
-
-          if (self.isSelect) {
-            var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; });
-            option.attr('value', itemValue);
-          }
-      });
-    },
-
-    /**
-     * Returns the items added as tags
-     */
-    items: function() {
-      return this.itemsArray;
-    },
-
-    /**
-     * Assembly value by retrieving the value of each item, and set it on the
-     * element.
-     */
-    pushVal: function() {
-      var self = this,
-          val = $.map(self.items(), function(item) {
-            return self.options.itemValue(item).toString();
-          });
-
-      self.$element.val(val, true);
-
-      if (self.options.triggerChange)
-        self.$element.trigger('change');
-    },
-
-    /**
-     * Initializes the tags input behaviour on the element
-     */
-    build: function(options) {
-      var self = this;
-
-      self.options = $.extend({}, defaultOptions, options);
-      // When itemValue is set, freeInput should always be false
-      if (self.objectItems)
-        self.options.freeInput = false;
-
-      makeOptionItemFunction(self.options, 'itemValue');
-      makeOptionItemFunction(self.options, 'itemText');
-      makeOptionItemFunction(self.options, 'itemThumb');
-      makeOptionFunction(self.options, 'tagClass');
-
-      // Typeahead Bootstrap version 2.3.2
-      if (self.options.typeahead) {
-        var typeahead = self.options.typeahead || {};
-
-        makeOptionFunction(typeahead, 'source');
-
-        self.$input.typeahead($.extend({}, typeahead, {
-          source: function (query, process) {
-            function processItems(items) {
-              var texts = [];
-
-              for (var i = 0; i < items.length; i++) {
-                var text = self.options.itemText(items[i]);
-                map[text] = items[i];
-                texts.push(text);
-              }
-              process(texts);
-            }
-
-            this.map = {};
-            var map = this.map,
-                data = typeahead.source(query);
-
-            if ($.isFunction(data.success)) {
-              // support for Angular callbacks
-              data.success(processItems);
-            } else if ($.isFunction(data.then)) {
-              // support for Angular promises
-              data.then(processItems);
-            } else {
-              // support for functions and jquery promises
-              $.when(data)
-                  .then(processItems);
-            }
-          },
-          updater: function (text) {
-            self.add(this.map[text]);
-            return this.map[text];
-          },
-          matcher: function (text) {
-            return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
-          },
-          sorter: function (texts) {
-            return texts.sort();
-          },
-          highlighter: function (text) {
-            var regex = new RegExp( '(' + this.query + ')', 'gi' );
-            return text.replace( regex, "<strong>$1</strong>" );
-          }
-        }));
-      }
-
-      // typeahead.js
-      if (self.options.typeaheadjs) {
-        var typeaheadConfig = null;
-        var typeaheadDatasets = {};
-
-        // Determine if main configurations were passed or simply a dataset
-        var typeaheadjs = self.options.typeaheadjs;
-        if ($.isArray(typeaheadjs)) {
-          typeaheadConfig = typeaheadjs[0];
-          typeaheadDatasets = typeaheadjs[1];
-        } else {
-          typeaheadDatasets = typeaheadjs;
-        }
-
-        self.$input.typeahead(typeaheadConfig, typeaheadDatasets).on('typeahead:selected', $.proxy(function (obj, datum) {
-          if (typeaheadDatasets.valueKey)
-            self.add(datum[typeaheadDatasets.valueKey]);
-          else
-            self.add(datum);
-          self.$input.typeahead('val', '');
-        }, self));
-      }
-
-      self.$container.on('click', $.proxy(function(event) {
-        if (! self.$element.attr('disabled')) {
-          self.$input.removeAttr('disabled');
-        }
-        self.$input.focus();
-      }, self));
-
-      if (self.options.addOnBlur && self.options.freeInput) {
-        self.$input.on('focusout', $.proxy(function(event) {
-          // HACK: only process on focusout when no typeahead opened, to
-          //       avoid adding the typeahead text as tag
-          if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) {
-            self.add(self.$input.val());
-            self.$input.val('');
-          }
-        }, self));
-      }
-
-      // Toggle the 'focus' css class on the container when it has focus
-      self.$container.on({
-        focusin: function() {
-          self.$container.addClass(self.options.focusClass);
-        },
-        focusout: function() {
-          self.$container.removeClass(self.options.focusClass);
-        },
-      });
-
-      self.$container.on('keydown', 'input', $.proxy(function(event) {
-        var $input = $(event.target),
-            $inputWrapper = self.findInputWrapper();
-
-        if (self.$element.attr('disabled')) {
-          self.$input.attr('disabled', 'disabled');
-          return;
-        }
-
-        switch (event.which) {
-            // BACKSPACE
-          case 8:
-            if (doGetCaretPosition($input[0]) === 0) {
-              var prev = $inputWrapper.prev();
-              if (prev.length) {
-                self.remove(prev.data('item'));
-              }
-            }
-            break;
-
-            // DELETE
-          case 46:
-            if (doGetCaretPosition($input[0]) === 0) {
-              var next = $inputWrapper.next();
-              if (next.length) {
-                self.remove(next.data('item'));
-              }
-            }
-            break;
-
-            // LEFT ARROW
-          case 37:
-            // Try to move the input before the previous tag
-            var $prevTag = $inputWrapper.prev();
-            if ($input.val().length === 0 && $prevTag[0]) {
-              $prevTag.before($inputWrapper);
-              $input.focus();
-            }
-            break;
-            // RIGHT ARROW
-          case 39:
-            // Try to move the input after the next tag
-            var $nextTag = $inputWrapper.next();
-            if ($input.val().length === 0 && $nextTag[0]) {
-              $nextTag.after($inputWrapper);
-              $input.focus();
-            }
-            break;
-          default:
-            // ignore
-        }
-
-        // Reset internal input's size
-        var textLength = $input.val().length,
-            wordSpace = Math.ceil(textLength / 5),
-            size = textLength + wordSpace + 1;
-        $input.attr('size', Math.max(this.inputSize, $input.val().length));
-      }, self));
-
-      self.$container.on('keypress', 'input', $.proxy(function(event) {
-        var $input = $(event.target);
-
-        if (self.$element.attr('disabled')) {
-          self.$input.attr('disabled', 'disabled');
-          return;
-        }
-
-        var text = $input.val(),
-            maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars;
-        if (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached) {
-          // Only attempt to add a tag if there is data in the field
-          if (self.options.freeInput && text.length !== 0) {
-            self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text);
-            $input.val('');
-          }
-
-          // If the field is empty, let the event triggered fire as usual
-          if (self.options.cancelConfirmKeysOnEmpty === false) {
-            event.preventDefault();
-          }
-        }
-
-        // Reset internal input's size
-        var textLength = $input.val().length,
-            wordSpace = Math.ceil(textLength / 5),
-            size = textLength + wordSpace + 1;
-        $input.attr('size', Math.max(this.inputSize, $input.val().length));
-      }, self));
-
-      // Remove icon clicked
-      self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
-        if (self.$element.attr('disabled')) {
-          return;
-        }
-        self.remove($(event.target).closest('.tag').data('item'));
-      }, self));
-
-      // Only add existing value as tags when using strings as tags
-      if (self.options.itemValue === defaultOptions.itemValue) {
-        if (self.$element[0].tagName === 'INPUT') {
-          self.add(self.$element.val());
-        } else {
-          $('option', self.$element).each(function() {
-            self.add($(this).attr('value'), true);
-          });
-        }
-      }
-    },
-
-    /**
-     * Removes all tagsinput behaviour and unregsiter all event handlers
-     */
-    destroy: function() {
-      var self = this;
-
-      // Unbind events
-      self.$container.off('keypress', 'input');
-      self.$container.off('click', '[role=remove]');
-
-      self.$container.remove();
-      self.$element.removeData('tagsinput');
-      self.$element.show();
-    },
-
-    /**
-     * Sets focus on the tagsinput
-     */
-    focus: function() {
-      this.$input.focus();
-    },
-
-    /**
-     * Returns the internal input element
-     */
-    input: function() {
-      return this.$input;
-    },
-
-    /**
-     * Returns the element which is wrapped around the internal input. This
-     * is normally the $container, but typeahead.js moves the $input element.
-     */
-    findInputWrapper: function() {
-      var elt = this.$input[0],
-          container = this.$container[0];
-      while(elt && elt.parentNode !== container)
-        elt = elt.parentNode;
-
-      return $(elt);
-    }
-  };
-
-  /**
-   * Register JQuery plugin
-   */
-  $.fn.tagsinput = function(arg1, arg2, arg3) {
-    var results = [];
-
-    this.each(function() {
-      var tagsinput = $(this).data('tagsinput');
-      // Initialize a new tags input
-      if (!tagsinput) {
-          tagsinput = new TagsInput(this, arg1);
-          $(this).data('tagsinput', tagsinput);
-          results.push(tagsinput);
-
-          if (this.tagName === 'SELECT') {
-              $('option', $(this)).attr('selected', 'selected');
-          }
-
-          // Init tags from $(this).val()
-          $(this).val($(this).val());
-      } else if (!arg1 && !arg2) {
-          // tagsinput already exists
-          // no function, trying to init
-          results.push(tagsinput);
-      } else if(tagsinput[arg1] !== undefined) {
-          // Invoke function on existing tags input
-            if(tagsinput[arg1].length === 3 && arg3 !== undefined){
-               var retVal = tagsinput[arg1](arg2, null, arg3);
-            }else{
-               var retVal = tagsinput[arg1](arg2);
-            }
-          if (retVal !== undefined)
-              results.push(retVal);
-      }
-    });
-
-    if ( typeof arg1 == 'string') {
-      // Return the results from the invoked function calls
-      return results.length > 1 ? results : results[0];
-    } else {
-      return results;
-    }
-  };
-
-  $.fn.tagsinput.Constructor = TagsInput;
-
-  /**
-   * Most options support both a string or number as well as a function as
-   * option value. This function makes sure that the option with the given
-   * key in the given options is wrapped in a function
-   */
-  function makeOptionItemFunction(options, key) {
-    if (typeof options[key] !== 'function') {
-      var propertyName = options[key];
-      options[key] = function(item) { return item[propertyName]; };
-    }
-  }
-  function makeOptionFunction(options, key) {
-    if (typeof options[key] !== 'function') {
-      var value = options[key];
-      options[key] = function() { return value; };
-    }
-  }
-  /**
-   * HtmlEncodes the given value
-   */
-  var htmlEncodeContainer = $('<div />');
-  function htmlEncode(value) {
-    if (value) {
-      return htmlEncodeContainer.text(value).html();
-    } else {
-      return '';
-    }
-  }
-
-  /**
-   * Returns the position of the caret in the given input field
-   * http://flightschool.acylt.com/devnotes/caret-position-woes/
-   */
-  function doGetCaretPosition(oField) {
-    var iCaretPos = 0;
-    if (document.selection) {
-      oField.focus ();
-      var oSel = document.selection.createRange();
-      oSel.moveStart ('character', -oField.value.length);
-      iCaretPos = oSel.text.length;
-    } else if (oField.selectionStart || oField.selectionStart == '0') {
-      iCaretPos = oField.selectionStart;
-    }
-    return (iCaretPos);
-  }
-
-  /**
-    * Returns boolean indicates whether user has pressed an expected key combination.
-    * @param object keyPressEvent: JavaScript event object, refer
-    *     http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
-    * @param object lookupList: expected key combinations, as in:
-    *     [13, {which: 188, shiftKey: true}]
-    */
-  function keyCombinationInList(keyPressEvent, lookupList) {
-      var found = false;
-      $.each(lookupList, function (index, keyCombination) {
-          if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
-              found = true;
-              return false;
-          }
-
-          if (keyPressEvent.which === keyCombination.which) {
-              var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey,
-                  shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey,
-                  ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
-              if (alt && shift && ctrl) {
-                  found = true;
-                  return false;
-              }
-          }
-      });
-
-      return found;
-  }
-
-  /**
-   * Initialize tagsinput behaviour on inputs and selects which have
-   * data-role=tagsinput
-   */
-  $(function() {
-    $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput();
-  });
-})(window.jQuery);
diff --git a/view/theme/frio/js/compose.js b/view/theme/frio/js/compose.js
new file mode 100644 (file)
index 0000000..88cd386
--- /dev/null
@@ -0,0 +1,57 @@
+$(function() {
+       // Jot attachment live preview.
+       let $textarea = $('textarea[name=body]');
+       $textarea.linkPreview();
+       $textarea.keyup(function(){
+               var textlen = $(this).val().length;
+               $('#character-counter').text(textlen);
+       });
+       $textarea.editor_autocomplete(baseurl + '/search/acl');
+       $textarea.bbco_autocomplete('bbcode');
+
+       let location_button = document.getElementById('profile-location');
+       let location_input = document.getElementById('jot-location');
+
+       if (location_button && location_input) {
+               updateLocationButtonDisplay(location_button, location_input);
+
+               location_input.addEventListener('change', function () {
+                       updateLocationButtonDisplay(location_button, location_input);
+               });
+               location_input.addEventListener('keyup', function () {
+                       updateLocationButtonDisplay(location_button, location_input);
+               });
+
+               location_button.addEventListener('click', function() {
+                       if (location_input.value) {
+                               location_input.value = '';
+                               updateLocationButtonDisplay(location_button, location_input);
+                       } else if ("geolocation" in navigator) {
+                               navigator.geolocation.getCurrentPosition(function(position) {
+                                       location_input.value = position.coords.latitude + ', ' + position.coords.longitude;
+                                       updateLocationButtonDisplay(location_button, location_input);
+                               }, function (error) {
+                                       location_button.disabled = true;
+                                       updateLocationButtonDisplay(location_button, location_input);
+                               });
+                       }
+               });
+       }
+});
+
+function updateLocationButtonDisplay(location_button, location_input)
+{
+       location_button.classList.remove('btn-primary');
+       if (location_input.value) {
+               location_button.disabled = false;
+               location_button.classList.add('btn-primary');
+               location_button.title = location_button.dataset.titleClear;
+       } else if (!"geolocation" in navigator) {
+               location_button.disabled = true;
+               location_button.title = location_button.dataset.titleUnavailable;
+       } else if (location_button.disabled) {
+               location_button.title = location_button.dataset.titleDisabled;
+       } else {
+               location_button.title = location_button.dataset.titleSet;
+       }
+}
index 597563fe1f81b1a828ddfebdc9d45556d4d3dd01..a068b4fe0e53385f1898873e1d0618bb11f0d63c 100644 (file)
@@ -49,24 +49,6 @@ $(document).ready(function() {
                $("#event-preview").empty();
                e.preventDefault();
        });
-
-       // Construct a new ACL. We need this everytime the 'event-edit-form' is loaded
-       // without page reloading (e.g. closing an old modal and open a new modal).
-       // Otherwise we wouldn't get the ACL data.
-       /// @todo: Try to implement some kind of ACL reloading in acl.js.
-
-       var eventPerms = document.getElementById('event-edit-form');
-
-       acl = new ACL(
-               baseurl + '/search/acl',
-               [
-                       JSON.parse(eventPerms.dataset.allow_cid),
-                       JSON.parse(eventPerms.dataset.allow_gid),
-                       JSON.parse(eventPerms.dataset.deny_cid),
-                       JSON.parse(eventPerms.dataset.deny_gid)
-               ]
-       );
-       acl.get(0, 100);
 });
 
 // Load the html of the actual event and incect the output to the
index f33988e13911120049d7064e7ec0aa151fe7fca8..c13b0682b581fbd2523478dd69c46e8c92544bc4 100644 (file)
@@ -159,20 +159,19 @@ Dialog.showJot = function() {
 // Init the filebrowser after page load.
 Dialog._load = function(url) {
        // Get nickname & filebrowser type from the modal content.
-       var nickname = $("#fb-nickname").attr("value");
-       var type = $("#fb-type").attr("value");
+       let filebrowser = document.getElementById('filebrowser');
 
        // Try to fetch the hash form the url.
-       var match = url.match(/fbrowser\/[a-z]+\/.*(#.*)/);
-       if (match===null) return; //not fbrowser
-       var hash = match[1];
+       let match = url.match(/fbrowser\/[a-z]+\/.*(#.*)/);
+       if (!filebrowser || match === null) {
+               return; //not fbrowser
+       }
 
        // Initialize the filebrowser.
-       var jsbrowser = function() {
-               FileBrowser.init(nickname, type, hash);
-       };
        loadScript("view/js/ajaxupload.js");
-       loadScript("view/theme/frio/js/filebrowser.js", jsbrowser);
+       loadScript("view/theme/frio/js/filebrowser.js", function() {
+               FileBrowser.init(filebrowser.dataset.nickname, filebrowser.dataset.type, match[1]);
+       });
 };
 
 /**
@@ -344,11 +343,11 @@ function toggleJotNav (elm) {
 
        // Minimize all tab content wrapper and activate only the selected
        // tab panel.
-       $('#jot-modal [role=tabpanel]').addClass("minimize").attr("aria-hidden" ,"true");
-       $('#jot-modal #' + tabpanel).removeClass("minimize").attr("aria-hidden" ,"false");
+       $('#profile-jot-form > [role=tabpanel]').addClass("minimize").attr("aria-hidden" ,"true");
+       $('#' + tabpanel).removeClass("minimize").attr("aria-hidden" ,"false");
 
        // Set the aria-selected states
-       $("#jot-modal .nav-tabs .jot-nav-lnk").attr("aria-selected", "false");
+       $("#jot-modal .modal-header .nav-tabs .jot-nav-lnk").attr("aria-selected", "false");
        elm.setAttribute("aria-selected", "true");
 
        // For some some tab panels we need to execute other js functions.
index 1dc4e94a4a8139c2bf6d3a6536ec459670277007..00555192c8a4af502ed713bc95457dd57b767ab6 100644 (file)
@@ -98,7 +98,6 @@ $("nav").bind('nav-update', function(e,data)
 });
 </script>
 <script src="<?=$frio?>/js/theme.js"></script>
-<script src="<?=$frio?>/js/acl.js"></script>
 <script src="<?=$frio?>/frameworks/bootstrap/js/bootstrap.min.js"></script>
 <script src="<?=$frio?>/frameworks/jasny/js/jasny-bootstrap.min.js"></script>
 <script src="<?=$frio?>/frameworks/bootstrap-select/js/bootstrap-select.min.js"></script>
index a9878efccaaf735d6929c2e74ca49856818962c4..6e76fc85d719f0fdfea8788b9da019c8d6283e7b 100644 (file)
@@ -128,3 +128,13 @@ aside .widget, .form-control, .panel, .nav-container, .wall-item-content, .e-con
     text-decoration-color: black;
     text-decoration-style: wavy;
 }
+
+/* New compose popup */
+.profile-jot-net {
+    background: #dff0d8;
+}
+
+.profile-jot-net summary {
+    color: #3c763d;
+    font-weight: bold;
+}
diff --git a/view/theme/frio/templates/acl_selector.tpl b/view/theme/frio/templates/acl_selector.tpl
deleted file mode 100644 (file)
index e335a4f..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-
-<div id="acl-wrapper">
-       <div class="form-group form-group-search">
-               <button id="acl-showall" class="btn btn-block btn-default"><i class="fa fa-globe"></i> {{$showall}}</button>
-       </div>
-       <div class="form-group form-group-search">
-               <input type="text" id="acl-search" class="form-control form-search" autocomplete="off">
-       </div>
-       <div id="acl-list">
-               <div id="acl-list-content"></div>
-       </div>
-       <span id="acl-fields"></span>
-</div>
-
-<div class="acl-list-item" rel="acl-template" style="display:none">
-       <img data-src="{0}" alt="{1}"><p>{1}</p>
-       <button class='acl-button-hide btn btn-sm btn-default'>{{$hide}}</button>
-       <button class='acl-button-show btn btn-sm btn-default'>{{$show}}</button>
-</div>
-
-{{if $networks}}
-<hr style="clear:both"/>
-<div class="form-group">
-       <label for="profile-jot-email" id="profile-jot-email-label">{{$emailcc}}</label>
-       <input type="text" name="emailcc" id="profile-jot-email" class="form-control" title="{{$emtitle}}" />
-</div>
-<div id="profile-jot-email-end"></div>
-
-       {{if $jotnets_fields}}
-               {{if $jotnets_fields|count < 3}}
-<div class="profile-jot-net">
-               {{else}}
-<details class="profile-jot-net">
-       <summary>{{$jotnets_summary}}</summary>
-               {{/if}}
-
-               {{foreach $jotnets_fields as $jotnets_field}}
-                       {{if $jotnets_field.type == 'checkbox'}}
-                               {{include file="field_checkbox.tpl" field=$jotnets_field.field}}
-                       {{elseif $jotnets_field.type == 'select'}}
-                               {{include file="field_select.tpl" field=$jotnets_field.field}}
-                       {{/if}}
-               {{/foreach}}
-
-               {{if $jotnets_fields|count >= 3}}
-</details>
-               {{else}}
-</div>
-               {{/if}}
-       {{/if}}
-{{/if}}
-
-<script type="text/javascript">
-$(document).ready(function() {
-       if(typeof acl=="undefined"){
-               acl = new ACL(
-                       baseurl + '/search/acl',
-                       [ {{$allowcid nofilter}},{{$allowgid nofilter}},{{$denycid nofilter}},{{$denygid nofilter}} ],
-                       {{$features.aclautomention}},
-                       {{if $APP->is_mobile}}true{{else}}false{{/if}}
-               );
-       }
-});
-</script>
index 661bdecb2664b92adeb121e7879f2dded971566a..c48d5c7fc8bba2d00a087e4bebd9a952bc25b9b6 100644 (file)
@@ -30,7 +30,7 @@
        </ul>
 
        <div id="event-edit-form-wrapper">
-       <form id="event-edit-form" action="{{$post}}" method="post" data-allow_cid="{{$allow_cid}}" data-allow_gid="{{$allow_gid}}" data-deny_cid="{{$deny_cid}}" data-deny_gid="{{$deny_gid}}">
+       <form id="event-edit-form" action="{{$post}}" method="post">
 
                <input type="hidden" name="event_id" value="{{$eid}}" />
                <input type="hidden" name="cid" value="{{$cid}}" />
index 48b9a63cbd587460413c7e7a6ce68ddf07851f7f..6d1e092d0cd4e4eef9d3e5aed39fb3f2f6368c02 100644 (file)
@@ -1,13 +1,10 @@
 <!--
        This is the template used by mod/fbrowser.php
 -->
-<div class="fbrowser {{$type}}">
+<div id="filebrowser" class="fbrowser {{$type}}" data-nickname="{{$nickname}}" data-type="{{$type}}">
        <div class="fbrowser-content">
-               <input id="fb-nickname" type="hidden" name="type" value="{{$nickname}}" />
-               <input id="fb-type" type="hidden" name="type" value="{{$type}}" />
-
                <div class="error hidden">
-                       <span></span> <button type="button" class="btn btn-link close" aria-label="Close">X</a>
+                       <span></span> <button type="button" class="btn btn-link close" aria-label="Close">X</button>
                </div>
 
                {{* The breadcrumb navigation *}}
index f944c80ae9ad0aaf234371ae2c7d706ad52efe25..eea3e738a5a629cd79edf8283f939db7b3e1ff07 100644 (file)
@@ -63,7 +63,6 @@
 <script type="text/javascript" src="view/asset/jquery-datetimepicker/build/jquery.datetimepicker.full.min.js"></script>
 <script type="text/javascript" src="view/asset/perfect-scrollbar/js/perfect-scrollbar.jquery.min.js"></script>
 <script type="text/javascript" src="view/asset/imagesloaded/imagesloaded.pkgd.min.js"></script>
-<script type="text/javascript" src="view/js/acl.js"></script>
 <script type="text/javascript" src="view/asset/base64/base64.min.js"></script>
 <script type="text/javascript" src="view/asset/dompurify/dist/purify.min.js"></script>
 <script type="text/javascript" src="view/js/main.js"></script>
index 71d598e23b65f6ade23a74906c2b202be6a59e03..d4a430eccfaaf76a14071106627b10763a23357a 100644 (file)
                                        </ul>
                                </div>
 
-                       </form>
+                               <div id="jot-fbrowser-wrapper" class="minimize" aria-labelledby="jot-browser-link" role="tabpanel" aria-hidden="true"></div>
 
-                       <div id="jot-fbrowser-wrapper" class="minimize" aria-labelledby="jot-browser-link" role="tabpanel" aria-hidden="true"></div>
+                       </form>
 
                        {{if $content}}<script type="text/javascript">initEditor();</script>{{/if}}
                </div>
index 6b4d2b880bc715b09ab1a8587971998e69f0ffc8..0ce009cdb72cc9a8614bed31c46b6654b312b81e 100644 (file)
@@ -1848,101 +1848,10 @@ h2 > .actionbutton {
   width: 690px;
   float: left;
 }
-#acl-search {
-  float: right;
-  background: #ffffff url("../../../images/search_18.png") no-repeat right center;
-  padding-right: 20px;
-}
-#acl-showall {
-  float: left;
-  display: block;
-  width: auto;
-  height: 18px;
-  background-color: #cccccc;
-  background-image: url("../../../images/show_all_off.png");
-  background-position: 7px 7px;
-  background-repeat: no-repeat;
-  padding: 7px 5px 0 30px;
-  color: #999999;
-  -moz-border-radius: 5px 5px 5px 5px;
-  -webkit-border-radius: 5px 5px 5px 5px;
-  border-radius: 5px 5px 5px 5px;
-}
-#acl-showall.selected {
-  color: #000000;
-  background-color: #ff9900;
-  background-image: url("../../../images/show_all_on.png");
-}
-#acl-list {
-  height: 210px;
-  border: 1px solid #cccccc;
-  clear: both;
-  margin-top: 30px;
-  overflow: auto;
-}
-.acl-list-item {
-  display: block;
-  width: 150px;
-  height: 30px;
-  border: 1px solid #cccccc;
-  margin: 5px;
-  float: left;
-}
-.acl-list-item img {
-  width: 22px;
-  height: 22px;
-  float: left;
-  margin: 4px;
-}
-.acl-list-item p {
-  height: 12px;
-  font-size: 10px;
-  margin: 0;
-  padding: 2px 0 1px;
-  overflow: hidden;
-}
-.acl-list-item a {
-  font-size: 8px;
-  display: block;
-  width: 40px;
-  height: 10px;
-  float: left;
-  color: #999999;
-  background-color: #cccccc;
-  background-position: 3px 3px;
-  background-repeat: no-repeat;
-  margin-right: 5px;
-  -webkit-border-radius: 2px ;
-  -moz-border-radius: 2px;
-  border-radius: 2px;
-  padding-left: 15px;
-}
 #acl-wrapper a:hover {
   text-decoration: none;
   color: #000000;
 }
-.acl-button-show {
-  background-image: url("../../../images/show_off.png");
-}
-.acl-button-hide {
-  background-image: url("../../../images/hide_off.png");
-}
-.acl-button-show.selected {
-  color: #000000;
-  background-color: #9ade00;
-  background-image: url("../../../images/show_on.png");
-}
-.acl-button-hide.selected {
-  color: #000000;
-  background-color: #ff4141;
-  background-image: url("../../../images/hide_on.png");
-}
-.acl-list-item.groupshow {
-  border-color: #9ade00;
-}
-.acl-list-item.grouphide {
-  border-color: #ff4141;
-}
 /** /acl **/
 /** tab buttons **/
 ul.tabs {
index 326a2fbfde9bd1120acaaae083a738ac1551916c..c0a1befad9a9995afec2539f40eb2c8259d7749b 100644 (file)
@@ -1848,101 +1848,10 @@ h2 > .actionbutton {
   width: 690px;
   float: left;
 }
-#acl-search {
-  float: right;
-  background: #ffffff url("../../../images/search_18.png") no-repeat right center;
-  padding-right: 20px;
-}
-#acl-showall {
-  float: left;
-  display: block;
-  width: auto;
-  height: 18px;
-  background-color: #cccccc;
-  background-image: url("../../../images/show_all_off.png");
-  background-position: 7px 7px;
-  background-repeat: no-repeat;
-  padding: 7px 5px 0 30px;
-  color: #999999;
-  -moz-border-radius: 5px 5px 5px 5px;
-  -webkit-border-radius: 5px 5px 5px 5px;
-  border-radius: 5px 5px 5px 5px;
-}
-#acl-showall.selected {
-  color: #000000;
-  background-color: #ff9900;
-  background-image: url("../../../images/show_all_on.png");
-}
-#acl-list {
-  height: 210px;
-  border: 1px solid #cccccc;
-  clear: both;
-  margin-top: 30px;
-  overflow: auto;
-}
-.acl-list-item {
-  display: block;
-  width: 150px;
-  height: 30px;
-  border: 1px solid #cccccc;
-  margin: 5px;
-  float: left;
-}
-.acl-list-item img {
-  width: 22px;
-  height: 22px;
-  float: left;
-  margin: 4px;
-}
-.acl-list-item p {
-  height: 12px;
-  font-size: 10px;
-  margin: 0;
-  padding: 2px 0 1px;
-  overflow: hidden;
-}
-.acl-list-item a {
-  font-size: 8px;
-  display: block;
-  width: 40px;
-  height: 10px;
-  float: left;
-  color: #999999;
-  background-color: #cccccc;
-  background-position: 3px 3px;
-  background-repeat: no-repeat;
-  margin-right: 5px;
-  -webkit-border-radius: 2px ;
-  -moz-border-radius: 2px;
-  border-radius: 2px;
-  padding-left: 15px;
-}
 #acl-wrapper a:hover {
   text-decoration: none;
   color: #000000;
 }
-.acl-button-show {
-  background-image: url("../../../images/show_off.png");
-}
-.acl-button-hide {
-  background-image: url("../../../images/hide_off.png");
-}
-.acl-button-show.selected {
-  color: #000000;
-  background-color: #9ade00;
-  background-image: url("../../../images/show_on.png");
-}
-.acl-button-hide.selected {
-  color: #000000;
-  background-color: #ff4141;
-  background-image: url("../../../images/hide_on.png");
-}
-.acl-list-item.groupshow {
-  border-color: #9ade00;
-}
-.acl-list-item.grouphide {
-  border-color: #ff4141;
-}
 /** /acl **/
 /** tab buttons **/
 ul.tabs {
index 064b60ba694859e8a18254462a8bf763a067d221..05cb05b1869327bb940ec6a8db1853d3ad612227 100644 (file)
@@ -1848,101 +1848,10 @@ h2 > .actionbutton {
   width: 690px;
   float: left;
 }
-#acl-search {
-  float: right;
-  background: #ffffff url("../../../images/search_18.png") no-repeat right center;
-  padding-right: 20px;
-}
-#acl-showall {
-  float: left;
-  display: block;
-  width: auto;
-  height: 18px;
-  background-color: #cccccc;
-  background-image: url("../../../images/show_all_off.png");
-  background-position: 7px 7px;
-  background-repeat: no-repeat;
-  padding: 7px 5px 0 30px;
-  color: #999999;
-  -moz-border-radius: 5px 5px 5px 5px;
-  -webkit-border-radius: 5px 5px 5px 5px;
-  border-radius: 5px 5px 5px 5px;
-}
-#acl-showall.selected {
-  color: #000000;
-  background-color: #ff9900;
-  background-image: url("../../../images/show_all_on.png");
-}
-#acl-list {
-  height: 210px;
-  border: 1px solid #cccccc;
-  clear: both;
-  margin-top: 30px;
-  overflow: auto;
-}
-.acl-list-item {
-  display: block;
-  width: 150px;
-  height: 30px;
-  border: 1px solid #cccccc;
-  margin: 5px;
-  float: left;
-}
-.acl-list-item img {
-  width: 22px;
-  height: 22px;
-  float: left;
-  margin: 4px;
-}
-.acl-list-item p {
-  height: 12px;
-  font-size: 10px;
-  margin: 0;
-  padding: 2px 0 1px;
-  overflow: hidden;
-}
-.acl-list-item a {
-  font-size: 8px;
-  display: block;
-  width: 40px;
-  height: 10px;
-  float: left;
-  color: #999999;
-  background-color: #cccccc;
-  background-position: 3px 3px;
-  background-repeat: no-repeat;
-  margin-right: 5px;
-  -webkit-border-radius: 2px ;
-  -moz-border-radius: 2px;
-  border-radius: 2px;
-  padding-left: 15px;
-}
 #acl-wrapper a:hover {
   text-decoration: none;
   color: #000000;
 }
-.acl-button-show {
-  background-image: url("../../../images/show_off.png");
-}
-.acl-button-hide {
-  background-image: url("../../../images/hide_off.png");
-}
-.acl-button-show.selected {
-  color: #000000;
-  background-color: #9ade00;
-  background-image: url("../../../images/show_on.png");
-}
-.acl-button-hide.selected {
-  color: #000000;
-  background-color: #ff4141;
-  background-image: url("../../../images/hide_on.png");
-}
-.acl-list-item.groupshow {
-  border-color: #9ade00;
-}
-.acl-list-item.grouphide {
-  border-color: #ff4141;
-}
 /** /acl **/
 /** tab buttons **/
 ul.tabs {
index 0c1c21a7b717846183efc5c66dfc7b63df014b7d..2406fea538a0541f28bf8ff9f144b7e43fa2e021 100644 (file)
@@ -1134,96 +1134,14 @@ h2 > .actionbutton { float: right; }
        display:block!important;
 }
 
-
-
 #acl-wrapper {
        width: 690px;
        float:left;
 }
-#acl-search {
-       float:right;
-       background: #ffffff url("../../../images/search_18.png") no-repeat right center;
-       padding-right:20px;
-}
-#acl-showall {
-       float: left;
-       display: block;
-       width: auto;
-       height: 18px;
-       background-color: #cccccc;
-       background-image: url("../../../images/show_all_off.png");
-       background-position: 7px 7px;
-       background-repeat: no-repeat;
-       padding: 7px 5px 0 30px;
-       color: #999999;
-       .rounded(5px);
-}
-#acl-showall.selected {
-       color: #000000;
-       background-color: #ff9900;
-       background-image: url("../../../images/show_all_on.png");
-}
-
-#acl-list {
-       height: 210px;
-       border: 1px solid #cccccc;
-       clear: both;
-       margin-top: 30px;
-       overflow: auto;
-}
-#acl-list-content {
-
-}
-.acl-list-item {
-       display: block;
-       width: 150px;
-       height: 30px;
-       border: 1px solid #cccccc;
-       margin: 5px;
-       float: left;
-}
-.acl-list-item img{
-       width:22px;
-       height: 22px;
-       float: left;
-       margin: 4px;
-}
-.acl-list-item p { height: 12px; font-size: 10px; margin: 0; padding: 2px 0 1px; overflow: hidden;}
-.acl-list-item a {
-       font-size: 8px;
-       display: block;
-       width: 40px;
-       height: 10px;
-       float: left;
-       color: #999999;
-       background-color: #cccccc;
-       background-position: 3px 3px;
-       background-repeat: no-repeat;
-       margin-right: 5px;
-       -webkit-border-radius: 2px ;
-       -moz-border-radius: 2px;
-       border-radius: 2px;
-       padding-left: 15px;
-}
 #acl-wrapper a:hover {
        text-decoration: none;
        color:#000000;
 }
-.acl-button-show { background-image: url("../../../images/show_off.png"); }
-.acl-button-hide { background-image: url("../../../images/hide_off.png"); }
-
-.acl-button-show.selected {
-       color: #000000;
-       background-color: #9ade00;
-       background-image: url("../../../images/show_on.png");
-}
-.acl-button-hide.selected {
-       color: #000000;
-       background-color: #ff4141;
-       background-image: url("../../../images/hide_on.png");
-}
-.acl-list-item.groupshow { border-color: #9ade00; }
-.acl-list-item.grouphide { border-color: #ff4141; }
 /** /acl **/
 
 /** tab buttons **/
index ea84f0166886d849f398b527d0994140872483aa..7e276f459753802ab1168a480c6e13e5c5dc86d8 100644 (file)
@@ -4138,108 +4138,11 @@ tools {
        width: 690px;
        float:left;
 }
-#acl-search {
-       float:right;
-       background: #ffffff url("../../../images/search_18.png") no-repeat right center;
-       padding-right: 20px;
-}
-
-#acl-showall {
-       float: left;
-       display: block;
-       font-size: 1em;
-       font-style: bold;
-       text-align: center;
-       padding: 3px;
-       margin-bottom: 5px;
-       background-color: #cccccc;
-       background-position: 7px 7px;
-       background-repeat: no-repeat;
-       padding: 5px;
-       border-radius: 5px;
-               -webkit-border-radius: 5px ;
-               -moz-border-radius: 5px;
-       color: #999999;
-}
-
-#acl-showall.selected {
-       color: #ffffff;
-       background-color: #1873a2;
-}
-
-#acl-list {
-       height: 400px;
-       border: 1px solid #cccccc;
-       background-color: #efefef;
-       clear: both;
-       margin-top: 30px;
-       overflow: auto;
-}
-
-#acl-list-content {
-}
-
-.acl-list-item {
-       display: block;
-       width: 155px;
-       height: 50px;
-       border: 1px solid #cccccc;
-       background-color: #fff;
-       margin: 5px;
-       float: left;
-       box-shadow: 2px 2px 3px #c1c1c1;
-               -moz-box-shadow: 2px 2px 3px #c1c1c1;
-               -webkit-box-shadow: 2px 2px 3px #c1c1c1;
-}
-.acl-list-item img {
-       width: 30px;
-       height: 30px;
-       float: left;
-       margin: 5px;
-}
-
-.acl-list-item p {
-       color: #999999;
-       height: 12px;
-       font-size: 0.7em;
-       margin: 0px;
-       padding: 2px 0px 1px;
-       overflow: hidden;
-}
-
-.acl-list-item a {
-       font-size: 10px;
-       display: block;
-       float: left;
-       color: #efefef;
-       background-color: #898989;
-       background-position: 3px 3px;
-       background-repeat: no-repeat;
-       margin: 10px 0 0 5px;
-       border-radius: 2px;
-               -webkit-border-radius: 2px ;
-               -moz-border-radius: 2px;
-       padding: 3px;
-}
-
 #acl-wrapper a:hover {
        text-decoration: none;
        background-color:#1873a2;
 }
 
-.acl-button-show.selected {
-       color: #efefef;
-       background-color: #1873a2;
-}
-
-.acl-button-hide .selected {
-       color: #efefef;
-       background-color: #a2a2a2;
-}
-
-.acl-list-item.groupshow { border-color: #1873a2; }
-.acl-list-item.grouphide { border-color: #a2a2a2; }
-
 /* ========================= */
 /* = Global Directory Link = */
 /* ========================= */
index c690cdf18014b7a26589a05981413e25e4934dec..07c452c7e04e051f8f1c14ed2a3574aadf7172a4 100644 (file)
@@ -70,9 +70,6 @@
         <div style="display: none;">
             <div id="profile-jot-acl-wrapper" style="width:auto;height:auto;overflow:auto;">
                 {{$acl nofilter}}
-                <hr style="clear:both"/>
-                <div id="profile-jot-email-label">{{$emailcc}}</div><input type="text" name="emailcc" id="profile-jot-email" title="{{$emtitle}}" />
-                <div id="profile-jot-email-end"></div>
                 {{$jotnets nofilter}}
             </div>
         </div>
index 9fbe4d347c52f12578672b522f5e53d6ae310836..f18076b5071f95ed9e647ce10d594e2992fa3b55 100644 (file)
@@ -88,15 +88,6 @@ table.smiley-preview{
        background-color: #252C33 !important;
 }
 
-/* ACL permission popup */
- .acl-list-item.groupshow {
-       border-color: #9ade00 !important;
-}
-
-.acl-list-item.grouphide {
-       border-color: #ff4141 !important;
-}
-
 /* Notifications */
 li.notify-unseen {
        background-color: #252C33;
index 7ad0717568b7cae0d9c86407493b5205aa7abaf4..caadf66ba1636b8c54bb70aa94b81ac31e1dd356 100644 (file)
@@ -226,24 +226,6 @@ aside.show {
 /* ACL window */
 #profile-jot-acl-wrapper, #profile-jot-acl-wrapper * { box-sizing: border-box; }
 #acl-wrapper { width: 100%; float: none; }
-#acl-search { width: 100%; float: none; padding-right: 0px; margin-bottom: 1em; }
-#acl-showall { width: 100%; height: 48px; margin-bottom: 1em; }
-.acl-list-item { width: auto; float: none; height: auto; overflow: hidden; position: relative;}
-.acl-list-item img { width: 48px; height: 48px; }
-.acl-list-item p { height: auto; font-size: inherit; }
-.acl-list-item a {
-  float: none;
-  position: absolute;
-  top: 5px;
-  right: 5px;
-  height: 48px;
-  padding: 10px 2px 2px 2px;
-  font-size: 12px;
-  width: 20%;
-  text-align: center;
-  background-position: center 5px;
-}
-.acl-list-item a.acl-button-hide { right: 25%; }
 /* flexbox for ACL window */
 #cboxLoadedContent,
 #cboxLoadedContent > div,
@@ -266,12 +248,6 @@ aside.show {
   -ms-flex: 1 100%;
   flex: 1 100%;
 }
-#acl-list {
-  -webkit-flex: 1 1 auto;
-  -moz-flex: 1 1 auto;
-  -ms-flex: 1 1 auto;
-  flex: 1 1 auto;  
-}
 
 /** input elements **/
 input,
index 7596ff5ca3fc6482756254418cd6de10a0a2b0b2..3c507de366c4e0841d0d83331f7587e99d23b446 100644 (file)
@@ -2123,101 +2123,10 @@ table.smiley-preview {
        width: 690px;
        float: left;
 }
-#acl-search {
-       float: right;
-       background: #ffffff url("../../../images/search_18.png") no-repeat right center;
-       padding-right: 20px;
-}
-#acl-showall {
-       float: left;
-       display: block;
-       width: auto;
-       height: 18px;
-       background-color: #cccccc;
-       background-image: url("../../../images/show_all_off.png");
-       background-position: 7px 7px;
-       background-repeat: no-repeat;
-       padding: 7px 5px 0px 30px;
-       color: #999999;
-       -moz-border-radius: 5px 5px 5px 5px;
-       -webkit-border-radius: 5px 5px 5px 5px;
-       border-radius: 5px 5px 5px 5px;
-}
-#acl-showall.selected {
-       color: #000000;
-       background-color: #ff9900;
-       background-image: url("../../../images/show_all_on.png");
-}
-#acl-list {
-       height: 210px;
-       border: 1px solid #cccccc;
-       clear: both;
-       margin-top: 30px;
-       overflow: auto;
-}
-.acl-list-item {
-       display: block;
-       width: 150px;
-       height: 30px;
-       border: 1px solid #cccccc;
-       margin: 5px;
-       float: left;
-}
-.acl-list-item img {
-       width: 22px;
-       height: 22px;
-       float: left;
-       margin: 4px;
-}
-.acl-list-item p {
-       height: 12px;
-       font-size: 10px;
-       margin: 0px;
-       padding: 2px 0px 1px;
-       overflow: hidden;
-}
-.acl-list-item a {
-       font-size: 8px;
-       display: block;
-       width: 40px;
-       height: 10px;
-       float: left;
-       color: #999999;
-       background-color: #cccccc;
-       background-position: 3px 3px;
-       background-repeat: no-repeat;
-       margin-right: 5px;
-       -webkit-border-radius: 2px ;
-       -moz-border-radius: 2px;
-       border-radius: 2px;
-       padding-left: 15px;
-}
 #acl-wrapper a:hover {
        text-decoration: none;
        color: #000000;
 }
-.acl-button-show {
-       background-image: url("../../../images/show_off.png");
-}
-.acl-button-hide {
-       background-image: url("../../../images/hide_off.png");
-}
-.acl-button-show.selected {
-       color: #000000;
-       background-color: #9ade00;
-       background-image: url("../../../images/show_on.png");
-}
-.acl-button-hide.selected {
-       color: #000000;
-       background-color: #ff4141;
-       background-image: url("../../../images/hide_on.png");
-}
-.acl-list-item.groupshow {
-       border-color: #9ade00;
-}
-.acl-list-item.grouphide {
-       border-color: #ff4141;
-}
 /** /acl **/
 /** tab buttons **/
 div.pager, ul.tabs {