Merge branch 'master' into zapp

This commit is contained in:
zotlabs 2018-04-28 13:55:03 -07:00
commit e26bfd76da
45 changed files with 3067 additions and 1717 deletions

View file

@ -1,3 +1,75 @@
Hubzilla 3.4 (????-??-??)
- Rename boxy schema to Focus-Boxy
- Rename BS-Default schema to Focus-Light
- Mark simple_* schemas unmaintained and deprecated - they will be removed in next release if nobody steps up to maintain them.
- Implement trending tags for mod pubstream
- Relax restrictions to the design tools menu to allow those with write_pages permission
- Add alt pager to mod moderate
- Show existing cover photo when changing it
- Update to bootstrap lib to version 4.1
- Provide a higher accuracy method for active channels information
- Provide visible star status for starred posts
- Move the thread author menu to the wall item photo
- Accept system_language through either get or post
- Remove recipient name from stored notifications but keep them in emails
- Fix issue of being forced to log back in after leaving a delegated channel
- Implement last commented expiration setting in mod admin
- Create catcloud widget and provide a type option which can include 'cards' or 'articles'
- Modified notifications widget to add the public stream when the current user is allowed to see it only
- Don't provide a connect button for transient identities
- Merge techlevels and features
- Implement auto-save posts and comments in browser using localStorage
- Display directory server in siteinfo.json
- Bring back the dnt policy document
- Implement OAuth2/OpenIDConnect server
- Add basic structure for additional features documentation
- Community tag refactor
- Obscurify chats
- Provide a way to share wiki pages
- Update folder timestamp on uploaded files
- Code optimisations and de-duplication on updating parent commented timestamp
- Turn newmember widget into a feature
- Make list mode work in cards and articles
- Make alt pager work for articles and cards
- Initial support for alternative sort orders on the cloud pages
- Add Ochannel module for testing OStatus bad behaviour
- Add the social - federation permission role
- Update justified gallery lib from 3.6.3 to 3.6.5
Bugfixes
- Fix regression with forum widget unseen count
- Fix issue with imagemagick exif info
- Aonymous comments in StdLimits shouldn't be allowed
- Fix wiki pages not syncing
- Show "Unseen public activity" channel setting when site only public streams are activated
- Fix channel import failing to provide channel_password value
- Fix permalinks to children of articles and cards
- Fix missing year on profile birthday input
- Fix missing login/out buttons for medium screensize
- Preserve existing categories when updating an app from an embed source
- Fix app sellpage not being stored
- Fix tagadelic being overly protective of permissions
- Fix comments not displayed in single card/article view
- Fix anonymous comments bump thread
- Fix pending registrations visible in admin accounts
Addons
Pubcrawl: fix issues with postgresql
Fuzzloc: new addon to blur your browser location
Pubcrawl: implement follow by webfinger
Cart: new addon which provides online shop functionalities (experimental)
Pubcrawl: implement two-way summary functionality
Wordpress: upgrade incutio xmlrpc library to use hubzilla curl wrapper
Hzfiles: various fixes
Diaspora: support full_name attribute in profile messages
Frphotos: deprecate plugin (keep it for reference)
Webmention: require html5 parser
GNU-Social: provide alternative xchan_url
Diaspora: fix wrong callback function
Diaspora: fix conversion of forum mentions to markdown by providing a !{forum@host} link syntax
Diaspora: fix item title not transferred
Hubzilla 3.2 (2018-03-09)
- Improve rendering of Readme files in plugin settings
- Add pdl file for mod moderate

View file

@ -9,6 +9,7 @@ namespace Zotlabs\Lib;
*/
class ActivityStreams {
public $raw = null;
public $data;
public $valid = false;
public $id = '';
@ -33,6 +34,7 @@ class ActivityStreams {
*/
function __construct($string) {
$this->raw = $string;
$this->data = json_decode($string, true);
if($this->data) {
$this->valid = true;

View file

@ -747,8 +747,8 @@ class Enotify {
// generate a mime boundary
$mimeBoundary = rand(0, 9) . "-"
.rand(10000000000, 9999999999) . "-"
.rand(10000000000, 9999999999) . "=:"
.rand(100000000, 999999999) . "-"
.rand(100000000, 999999999) . "=:"
.rand(10000, 99999);
// generate a multipart/alternative message header

View file

@ -268,15 +268,15 @@ class Acl extends \Zotlabs\Web\Controller {
});
}
}
if(intval(get_config('system','taganyone')) || intval(get_pconfig(local_channel(),'system','taganyone'))) {
if((count($r) < 100) && $type == 'c') {
$r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
FROM xchan
WHERE xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc"
);
if($r2)
$r = array_merge($r,$r2);
}
if((count($r) < 100) && $type == 'c') {
$r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags, 0 as abook_self
FROM xchan
WHERE xchan_deleted = 0 and not xchan_network in ('rss','anon','unknown') $sql_extra2 order by $order_extra2 xchan_name asc"
);
if($r2) {
$r = array_merge($r,$r2);
$r = unique_multidim_array($r,'hash');
}
}
}
elseif($type == 'm') {
@ -337,24 +337,23 @@ class Acl extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $g) {
if(($g['network'] === 'rss') && ($type != 'a'))
if(in_array($g['network'],['rss','anon','unknown']) && ($type != 'a'))
continue;
$g['hash'] = urlencode($g['hash']);
if(! $g['nick']) {
$t = explode(' ',strtolower($g['name']));
$g['nick'] = $t[0] . '@';
$g['nick'] = $g['url'];
}
if(in_array($g['hash'],$permitted) && in_array($type, [ 'c', 'f' ]) && (! $noforums)) {
if(in_array($g['hash'],$permitted) && $type === 'f' && (! $noforums)) {
$contacts[] = array(
"type" => "c",
"photo" => "images/twopeople.png",
"name" => $g['name'] . (($type === 'f') ? '' : '+'),
"id" => urlencode($g['id']) . (($type === 'f') ? '' : '+'),
"name" => $g['name'],
"id" => urlencode($g['id']),
"xid" => $g['hash'],
"link" => $g['nick'],
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
"nick" => substr($g['nick'],0,strpos($g['nick'],'@')),
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
"taggable" => 'taggable',
@ -368,8 +367,8 @@ class Acl extends \Zotlabs\Web\Controller {
"name" => $g['name'],
"id" => urlencode($g['id']),
"xid" => $g['hash'],
"link" => $g['nick'],
"nick" => (($g['nick']) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
"link" => (($g['nick']) ? $g['nick'] : $g['url']),
"nick" => ((strpos($g['nick'],'@')) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
"self" => (intval($g['abook_self']) ? 'abook-self' : ''),
"taggable" => '',
"label" => '',

View file

@ -218,15 +218,13 @@ class Network extends \Zotlabs\Web\Controller {
$contact_str = '';
$contacts = group_get_members($group);
if($contacts) {
foreach($contacts as $c) {
if($contact_str)
$contact_str .= ',';
$contact_str .= "'" . $c['xchan'] . "'";
}
$contact_str = ids_to_querystr($contacts,'xchan',true);
}
else {
$contact_str = ' 0 ';
info( t('Privacy group is empty'));
$contact_str = " '0' ";
if(! $update) {
info( t('Privacy group is empty'));
}
}
$item_thread_top = '';
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str )) or allow_gid like '" . protect_sprintf('%<' . dbesc($group_hash) . '>%') . "' ) and id = parent $item_normal ) ";
@ -480,7 +478,6 @@ class Network extends \Zotlabs\Web\Controller {
$ordering = "commented";
if($load) {
// Fetch a page full of parent items for this page
$r = q("SELECT item.parent AS item_id FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )

View file

@ -1148,10 +1148,10 @@ class Photos extends \Zotlabs\Web\Controller {
builtin_activity_puller($item, $conv_responses);
}
$like_count = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid']] : '');
$like_list = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid'] . '-l'] : '');
if (count($like_list) > MAX_LIKERS) {
if(is_array($like_list) && (count($like_list) > MAX_LIKERS)) {
$like_list_part = array_slice($like_list, 0, MAX_LIKERS);
array_push($like_list_part, '<a href="#" data-toggle="modal" data-target="#likeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {
@ -1163,7 +1163,7 @@ class Photos extends \Zotlabs\Web\Controller {
$dislike_count = ((x($dlike,$link_item['mid'])) ? $dlike[$link_item['mid']] : '');
$dislike_list = ((x($dlike,$link_item['mid'])) ? $dlike[$link_item['mid'] . '-l'] : '');
$dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun');
if (count($dislike_list) > MAX_LIKERS) {
if (is_array($dislike_list) && (count($dislike_list) > MAX_LIKERS)) {
$dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS);
array_push($dislike_list_part, '<a href="#" data-toggle="modal" data-target="#dislikeModal-' . $this->get_id() . '"><b>' . t('View all') . '</b></a>');
} else {

View file

@ -169,7 +169,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
$x = attach_syspaths($this->auth->owner_id,$this->folder_hash);
$y = q("update attach set display_path = '%s where hash = '%s' and uid = %d",
$y = q("update attach set display_path = '%s' where hash = '%s' and uid = %d",
dbesc($x['path']),
dbesc($this->folder_hash),
intval($this->auth->owner_id)
@ -389,8 +389,12 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
);
if ($r) {
// When initiated from DAV, set the 'force' flag on attach_mkdir(). This will cause the operation to report success even if the
// folder already exists.
require_once('include/attach.php');
$result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash));
$result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash, 'force' => true));
if($result['success']) {
$sync = attach_export_data($r[0],$result['data']['hash']);

View file

@ -66,8 +66,8 @@ class Forums {
for($x = 0; $x < count($r1); $x ++) {
$r = q("select sum(item_unseen) as unseen from item
where uid = %d and owner_xchan = '%s' and item_unseen = 1 $perms_sql ",
dbesc($r1[$x]['xchan_hash']),
intval(local_channel())
intval(local_channel()),
dbesc($r1[$x]['xchan_hash'])
);
if($r)
$r1[$x]['unseen'] = $r[0]['unseen'];

View file

@ -51,10 +51,9 @@ require_once('include/bbcode.php');
require_once('include/zot6.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '3.5' );
define ( 'STD_VERSION', '3.5.2' );
define ( 'ZOT_REVISION', '6.0b' );
define ( 'DB_UPDATE_VERSION', 1212 );
define ( 'PROJECT_BASE', __DIR__ );

179
doc/fr/project.bb Normal file
View file

@ -0,0 +1,179 @@
[h3]La gouvernance de $Projectname [/h3]
La gouvernance est liée à la gestion d'un projet et plus particulièrement à la résolution des conflits.
[h4]Gouvernance communautaire[/h4]
Le projet est maintenu et les décisions sont prises par la " communauté ". La structure de gouvernance continue d'évoluer. Jusqu'à ce que la structure soit finalisée, les décisions sont prises dans l'ordre suivant :
[ol]
[*] Consensus paresseux
Si une proposition de projet est soumise à l'un des forums de gouvernance communautaire et qu'il n'y a pas d'objections sérieuses dans un délai "raisonnable" à partir de la date de la proposition (nous accordons généralement 2 à 3 jours pour que toutes les parties intéressées puissent intervenir), aucun vote n'est nécessaire et la proposition sera considérée comme approuvée. Certaines préoccupations peuvent être soulevées à ce moment-, mais si elles sont abordées au cours de la discussion et des solutions de rechange fournies, elles seront quand même considérées comme approuvées.
[*] Veto
Les promoteurs principaux ayant un historique important d'engagements de projet peuvent opposer leur veto à toute décision. La décision ne peut être prise tant que le veto n'a pas é levé ou qu'une autre proposition n'a pas é présentée.
[*] Vote de la communauté
Une décision qui n'a pas de mandat clair ou de consensus clair, mais qui ne fait pas l'objet d'un veto, peut être soumise au vote de la communauté. Actuellement, il s'agit d'un simple vote populaire dans l'un des forums communautaires applicables. À ce moment-, c'est le vote populaire qui décide du résultat. Cela pourrait changer à l'avenir si la communauté adopte un modèle de gouvernance de " conseil ". Ce document sera mis à jour à ce moment- avec les règles de gouvernance mises à jour.
[/ol]
Le vote communautaire n'offre pas toujours un résultat agréable et peut générer des factions polarisées au sein de la communauté (d' la raison pour laquelle d'autres modèles sont à l'étude). Si la proposition est rejetée, il y a encore plusieurs choses qui peuvent être faites et la proposition peut être soumise à nouveau avec des paramètres légèrement différents (conversion vers un module complémentaire, conversion vers un module optionnel qui est désactivé par défaut, etc. Si l'intérêt pour le dispositif est élevé et que le vote est " serré ", cela peut générer beaucoup de mauvais sentiments parmi les électeurs perdants. Lors de ces votes serrés, il est [b]fortement recommandé[/b] que l'auteur de la proposition prenne des mesures pour répondre à toute préoccupation soulevée et la soumettre de nouveau.
[h4]Politique de confidentialité[/h4]
Q: Qui peut voir mon contenu ?
R : Par défaut, N'IMPORTE QUELLE personne sur Internet, à MOINS que vous le restreigniez. Nom du projet vous permet de choisir le niveau de confidentialité que vous désirez. Le contenu restreint ne sera PAS visible pour les "réseaux d'espionnage" et les annonceurs. Il sera protégé contre les écoutes de l'extérieur - au mieux de nos capacités. Les administrateurs de Hub ayant suffisamment de compétences et de patience PEUVENT être en mesure d'écouter certaines communications privées, mais ils doivent déployer des trésors d'efforts pour le faire. Des modes de confidentialité existent au sein de $Projectname qui résistent même à l'écoute par des administrateurs de hub qualifiés et déterminés.
Q : Mon contenu peut-il être censuré ?
R : $Nom du projet (le réseau) NE PEUT PAS censurer votre contenu. Les administrateurs de serveur et de hub sont soumis aux lois locales et PEUVENT supprimer le contenu répréhensible de leur site/hub. N'importe qui PEUT devenir un administrateur de hub, y compris vous ; et donc publier du contenu qui pourrait autrement être censuré. Vous POUVEZ toujours être soumis aux lois locales.
[h5]Définitions[/h5].
**$Nom du projet****
Autrement appelé "le réseau", $Projectname est une collection d'ordinateurs/serveurs individuels (aka **hubs**) qui se connectent ensemble pour former un plus grand réseau coopératif.
**hub**
Un ordinateur individuel ou un serveur connecté à $Projectname. Ces services sont fournis par un **administrateur de hub** et peuvent être publics ou privés, payants ou gratuits.
**administrateur de hub****
Gérant du système d'un hub individuel.
[h5]Politiques[/h5]
**Information publique**
Toute information ou tout ce que vous affichez dans $Projectname PEUT être public ou visible par quiconque sur Internet. Dans la mesure du possible, $Projectname vous permet de protéger le contenu et de restreindre qui peut le consulter.
La photo de votre profil, le nom de votre canal et l'emplacement (URL ou adresse réseau) de votre canal sont visibles par tous sur Internet et les contrôles de confidentialité n'affecteront pas l'affichage de ces éléments.
Vous POUVEZ fournir en plus d'autres informations de profil. Toute information que vous fournissez dans votre profil "par défaut" ou **profil public** PEUT être transmise à d'autres hubs dans $Projectname et peut également être affichée dans le répertoire des canaux. Vous pouvez limiter l'affichage de ces informations de profil. Il peut être limité aux seuls membres de votre hub, ou seulement aux connexions (amis), ou à d'autres groupes limités de visionneurs comme vous le souhaitez. Si vous souhaitez que votre profil soit restreint, vous devez définir le paramètre de confidentialité approprié ou simplement NE PAS fournir d'informations supplémentaires.
**Contenu**
Le contenu que vous fournissez (messages de statut, photos, fichiers, etc.) vous appartient. Par défaut, $Projectname publie le contenu ouvertement et visible par tout le monde sur Internet (PUBLIC). Vous POUVEZ contrôler cela dans les paramètres de votre canal et restreindre les permissions par défaut ou vous POUVEZ restreindre la visibilité de n'importe quel élément publié séparément (PRIVÉ). Les développeurs de noms de projet s'assureront que le contenu restreint est visible SEULEMENT pour ceux qui figurent dans la liste des restrictions - au mieux de leurs capacités.
Les contenus (en particulier les messages de statut) que vous partagez avec d'autres réseaux ou que vous avez rendus visibles à quiconque sur Internet (PUBLIC) ne peuvent pas être facilement repris une fois qu'ils ont é publiés. Il PEUT être partagé avec d'autres réseaux et rendu disponible par le biais de flux RSS/Atom. Il peut aussi être syndiqué sur d'autres sites $Projectname. Il PEUT apparaître sur d'autres réseaux et sites Web et être visible dans les recherches sur Internet. Si vous ne souhaitez pas ce comportement par défaut, veuillez ajuster les paramètres de votre canal et restreindre le nombre de personnes qui peuvent voir votre contenu.
**Commentaires et posts du Forum**
Les commentaires sur les posts qui ont é créés par d'autres et les posts qui sont désignés comme posts du forum vous appartiennent en tant que créateur/auteur, mais la distribution de ces posts n'est pas sous votre contrôle direct, et vous renoncez à certains droits sur ces items. Ces messages/commentaires PEUVENT être redistribués à d'autres, et PEUVENT être visibles pour n'importe qui sur Internet. Dans le cas de commentaires, le créateur du "premier message" dans le fil de discussion (conversation) auquel vous répondez contrôle la distribution de tous les commentaires et réponses à ce message. Ils "possèdent" et ont donc certains droits sur l'ensemble de la conversation (y compris tous les commentaires qu'elle contient). Vous pouvez toujours modifier ou supprimer le commentaire, mais le propriétaire de la conversation a également le droit de modifier, supprimer, redistribuer et sauvegarder/restaurer tout ou partie du contenu de la conversation.
**Les informations privées**
Les développeurs de $Projectname s'assureront que tout contenu que vous fournissez et qui est désigné comme PRIVÉ seront protégés contre les écoutes - au mieux de leurs capacités. Le contenu des canaux privés PEUT être vu dans la base de données de chaque administrateur de hub impliqué, mais les messages privés sont masqués dans la base de données. Cette dernière signifie qu'il est très difficile, mais PAS impossible que ce contenu soit vu par un administrateur de hub. Le contenu du canal privé et les messages privés sont également éliminés des notifications par courriel. Le cryptage de bout en bout est fourni en option et ceci NE PEUT PAS être vu, même par un administrateur déterminé.
[h5]Confidentialité de l'identité[/h5].
La confidentialité de votre identité est un autre aspect. Parce que vous avez une identité décentralisée dans $Projectname, votre vie privée s'étend au-delà de votre hub d'origine. Si vous voulez avoir le contrôle total de votre vie privée et de la sécurité, vous devriez faire fonctionner votre propre concentrateur sur un serveur dédié. Pour beaucoup de gens, c'est compliqué et cela peut mettre à l'épreuve leurs capacités techniques. Énumérons donc quelques précautions que vous pouvez prendre pour assurer votre vie privée autant que possible.
Une identité décentralisée a beaucoup d'avantages et vous donne beaucoup de fonctionnalités intéressantes, mais vous devez être conscient du fait que votre identité est connue par d'autres hubs dans le réseau $Projectname. L'un de ces avantages est que d'autres canaux peuvent vous servir du contenu personnalisé et vous permettre de voir des choses privées (comme des photos privées que d'autres souhaitent partager avec vous). Pour cette raison, ces canaux ont besoin de savoir qui vous êtes. Mais nous comprenons que parfois, ces autres canaux en savent plus de vous que vous ne le souhaiteriez. Par exemple, le plug-in Visage qui peut indiquer au propriétaire d'un canal la dernière fois que vous avez visité son profil. Vous pouvez facilement OPT-OUT de ce bas niveau et nous pensons, le suivi inoffensif.
Vous pouvez activer [Ne pas suivre (DNT)](http://donottrack.us/) dans votre navigateur Web. Nous respectons cette nouvelle proposition de politique de confidentialité. Tous les navigateurs modernes supportent le DNT. Vous le trouverez dans les paramètres de confidentialité de vos navigateurs ou bien vous pouvez consulter le manuel du navigateur Web. Cela n'affectera pas la fonctionnalité de $Projectname. Ce réglage est probablement suffisant pour la plupart des gens.
*Vous pouvez [désactiver la publication](settings) de votre chaîne dans notre répertoire de chaînes. Si vous voulez que les gens trouvent votre canal, vous devriez leur donner l'adresse de votre canal directement. Nous pensons que c'est une bonne indication que vous préférez une vie privée supplémentaire et que vous activez automatiquement l'option "Ne pas suivre" si c'est le cas.
*Vous pouvez avoir un hub bloqué. Cela signifie que tous les canaux et le contenu de cette hub ne sont pas publics et ne sont pas visibles pour le monde extérieur. C'est quelque chose que seul votre administrateur de hub peut faire. Nous respectons également ce principe et activons automatiquement l'option "Ne pas suivre" si elle est définie.
[h5]La Censure[/h5]
$Projectname est un réseau mondial qui inclut toutes les religions et toutes les cultures. Cela n'implique pas que tous les membres du réseau ressentent la même chose que vous sur les questions litigieuses, et certaines personnes peuvent être FORTEMENT opposées au contenu que vous publiez. En général, si vous souhaitez publier quelque chose que vous savez ne pas être universellement acceptable, la meilleure approche est de limiter l'audience en utilisant les contrôles de confidentialité à un petit cercle d'amis.
$Projectname en tant que fournisseur de réseau n'est pas en mesure de censurer le contenu. Cependant, les administrateurs du hub PEUVENT censurer tout contenu qui apparaît sur leur hub pour se conformer aux lois locales ou même au jugement personnel. Leur décision est finale. Si vous avez des problèmes avec un administrateur de hub, vous pouvez déplacer votre compte et vos messages sur un autre site qui correspond mieux à vos attentes. Veuillez vérifier (périodiquement) les[Conditions d'utilisation](help/TermsOfService) de votre hub pour connaître les règles ou directives. Si votre contenu se compose de matériel qui est illégal ou qui peut causer des problèmes, vous êtes FORTEMENT encouragé à héberger le vôtre (devenez un administrateur de hub). Vous pouvez toujours trouver que votre contenu est bloqué sur certains hubs, mais $Projectname en tant que réseau ne peut pas l'empêcher d'être posté.
$Projectname RECOMMANDE que les administrateurs du concentrateur accordent un délai de grâce de 1 à 2 jours entre l'avertissement au titulaire du compte du contenu qui doit être supprimé et la suppression ou la désactivation physique du compte. Cela donnera au propriétaire du contenu la possibilité d'exporter les métadonnées de son canal et de les importer sur un autre site. Dans de rares cas, le contenu peut être de nature à justifier la résiliation immédiate du compte. Il s'agit d'une décision de hub, pas d'une décision de $Projectname.
Si vous publiez régulièrement des contenus à caractère adulte ou offensant, nous vous encourageons fortement à marquer votre compte "NSFW" (Not Safe For Work). Ceci empêchera l'affichage de votre photo de profil dans le répertoire, sauf pour les visiteurs qui ont choisi de désactiver le "safe mode". Si votre photo de profil est trouvée par les administrateurs d'annuaire comme étant adulte ou offensante, l'administrateur d'annuaire PEUT marquer votre photo de profil comme NSFW. Il n'existe actuellement aucun mécanisme officiel pour contester ou renverser cette décision, c'est pourquoi vous DEVEZ marquer votre propre compte NSFW s'il est susceptible d'être inapproprié pour le grand public.
[h3]Remerciements[/h3]
Merci à tous ceux qui ont aidé et contribué au projet et à ses prédécesseurs au fil des ans.
Il est possible que votre nom nous ait échappé, mais ce n'est pas intentionnel. Nous remercions également la collectivité et ses membres pour leur précieuse contribution et sans qui tout cet effort n'aurait pas de sens.
Il convient également de reconnaître les contributions et les solutions aux problèmes qui sont apparus à la suite de des discussions entre les membres et les développeurs d'autres projets quelque peu liés et concurrents ; même si nous avons eu nos désaccords occasionnels.
[list]
[li]Mike Macgirvin[/li]
[li]Fabio Comuni[/li]
[li]Simon L'nu[/li]
[li]marijus[/li]
[li]Tobias Diekershoff[/li]
[li]fabrixxm[/li]
[li]tommy tomson[/li]
[li]Simon[/li]
[li]zottel[/li]
[li]Christian Vogeley[/li]
[li]jeroenpraat[/li]
[li]Michael Vogel[/li]
[li]erik[/li]
[li]Zach Prezkuta[/li]
[li]Paolo T[/li]
[li]Michael Meer[/li]
[li]Michael[/li]
[li]Abinoam P. Marques Jr[/li]
[li]Tobias Hößl[/li]
[li]Alexander Kampmann[/li]
[li]Olaf Conradi[/li]
[li]Paolo Tacconi[/li]
[li]tobiasd[/li]
[li]Devlon Duthie[/li]
[li]Zvi ben Yaakov (a.k.a rdc)[/li]
[li]Alexandre Hannud Abdo[/li]
[li]Olivier Migeot[/li]
[li]Chris Case[/li]
[li]Klaus Weidenbach[/li]
[li]Michael Johnston[/li]
[li]olivierm[/li]
[li]Vasudev Kamath[/li]
[li]pixelroot[/li]
[li]Max Weller[/li]
[li]duthied[/li]
[li]Martin Schmitt[/li]
[li]Sebastian Egbers[/li]
[li]Erkan Yilmaz[/li]
[li]sasiflo[/li]
[li]Stefan Parviainen[/li]
[li]Haakon Meland Eriksen[/li]
[li]Oliver Hartmann (23n)[/li]
[li]Erik Lundin[/li]
[li]habeascodice[/li]
[li]sirius[/li]
[li]Charles[/li]
[li]Tony Baldwin[/li]
[li]Hauke Zuehl[/li]
[li]Keith Fernie[/li]
[li]Anne Walk[/li]
[li]toclimb[/li]
[li]Daniel Frank[/li]
[li]Matthew Exon[/li]
[li]Michal Supler[/li]
[li]Tobias Luther[/li]
[li]U-SOUND\mike[/li]
[li]mrjive[/li]
[li]nostupidzone[/li]
[li]tonnerkiller[/li]
[li]Antoine G[/li]
[li]Christian Drechsler[/li]
[li]Ludovic Grossard[/li]
[li]RedmatrixCanada[/li]
[li]Stanislav Lechev [0xAF][/li]
[li]aweiher[/li]
[li]bufalo1973[/li]
[li]dsp1986[/li]
[li]felixgilles[/li]
[li]ike[/li]
[li]maase2[/li]
[li]mycocham[/li]
[li]ndurchx[/li]
[li]pafcu[/li]
[li]Simó Albert i Beltran[/li]
[li]Manuel Reva[/li]
[li]Manuel Jiménez Friaza[/li]
[li]Gustav Wall aka "neue medienordnung plus"[/li]
[/list]

View file

@ -2286,33 +2286,22 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
if(! ($c && $resource_id))
return false;
// find the resource to be moved
$r = q("select * from attach where hash = '%s' and uid = %d limit 1",
dbesc($resource_id),
intval($channel_id)
);
if(! $r)
if(! $r) {
logger('resource_id not found');
return false;
}
$oldstorepath = dbunescbin($r[0]['content']);
if($r[0]['is_dir']) {
$move_success = true;
$x = q("select hash from attach where folder = '%s' and uid = %d",
dbesc($r[0]['hash']),
intval($channel_id)
);
if($x) {
foreach($x as $xv) {
$rs = attach_move($channel_id,$xv['hash'],$r[0]['hash']);
if(! $rs) {
$move_success = false;
break;
}
}
}
return $move_success;
}
// find the resource we are moving to
if($new_folder_hash) {
$n = q("select * from attach where hash = '%s' and uid = %d and is_dir = 1 limit 1",
@ -2326,6 +2315,10 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
$newstorepath = dbunescbin($n[0]['content']) . '/' . $resource_id;
}
else {
// root directory
$newdirname = EMPTY_STR;
$newstorepath = 'store/' . $c['channel_address'] . '/' . $resource_id;
}
@ -2335,56 +2328,61 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
$filename = $r[0]['filename'];
$s = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ",
dbesc($filename),
dbesc($new_folder_hash)
);
// don't do duplicate check unless our parent folder has changed.
if($s) {
$overwrite = get_pconfig($channel_id,'system','overwrite_dup_files');
if($overwrite) {
/// @fixme
return;
}
else {
if(strpos($filename,'.') !== false) {
$basename = substr($filename,0,strrpos($filename,'.'));
$ext = substr($filename,strrpos($filename,'.'));
if($r[0]['folder'] !== $new_folder_hash) {
$s = q("select filename, id, hash, filesize from attach where filename = '%s' and folder = '%s' ",
dbesc($filename),
dbesc($new_folder_hash)
);
if($s) {
$overwrite = get_pconfig($channel_id,'system','overwrite_dup_files');
if($overwrite) {
/// @fixme
return;
}
else {
$basename = $filename;
$ext = '';
}
$matches = false;
if(preg_match('/(.*?)\([0-9]{1,}\)$/',$basename,$matches))
$basename = $matches[1];
$v = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' ",
dbesc($basename . $ext),
dbesc($basename . '(%)' . $ext),
dbesc($new_folder_hash)
);
if($v) {
$x = 1;
do {
$found = false;
foreach($v as $vv) {
if($vv['filename'] === $basename . '(' . $x . ')' . $ext) {
$found = true;
break;
}
}
if($found)
$x++;
if(strpos($filename,'.') !== false) {
$basename = substr($filename,0,strrpos($filename,'.'));
$ext = substr($filename,strrpos($filename,'.'));
}
while($found);
$filename = $basename . '(' . $x . ')' . $ext;
else {
$basename = $filename;
$ext = '';
}
$matches = false;
if(preg_match('/(.*?)\([0-9]{1,}\)$/',$basename,$matches))
$basename = $matches[1];
$v = q("select filename from attach where ( filename = '%s' OR filename like '%s' ) and folder = '%s' ",
dbesc($basename . $ext),
dbesc($basename . '(%)' . $ext),
dbesc($new_folder_hash)
);
if($v) {
$x = 1;
do {
$found = false;
foreach($v as $vv) {
if($vv['filename'] === $basename . '(' . $x . ')' . $ext) {
$found = true;
break;
}
}
if($found)
$x++;
}
while($found);
$filename = $basename . '(' . $x . ')' . $ext;
}
else
$filename = $basename . $ext;
}
else
$filename = $basename . $ext;
}
}
@ -2423,6 +2421,24 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
);
}
if($r[0]['is_dir']) {
$move_success = true;
$x = q("select hash from attach where folder = '%s' and uid = %d",
dbesc($r[0]['hash']),
intval($channel_id)
);
if($x) {
foreach($x as $xv) {
$rs = attach_move($channel_id,$xv['hash'],$r[0]['hash']);
if(! $rs) {
$move_success = false;
break;
}
}
}
return $move_success;
}
return true;
}

View file

@ -85,12 +85,14 @@ function tryoembed($match) {
function nakedoembed($match) {
$url = ((count($match) == 2) ? $match[1] : $match[2]);
$o = oembed_fetch_url($url);
$strip_url = strip_escaped_zids($url);
$o = oembed_fetch_url($strip_url);
if ($o['type'] == 'error')
return $match[0];
return str_replace($url,$strip_url,$match[0]);
return '[embed]' . $url . '[/embed]';
return '[embed]' . $strip_url . '[/embed]';
}
function tryzrlaudio($match) {

View file

@ -2240,6 +2240,11 @@ function get_zcard_embed($channel, $observer_hash = '', $args = array()) {
* - false if no channel with $nick was found
*/
function channelx_by_nick($nick) {
// If we are provided a Unicode nickname convert to IDN
$nick = punify($nick);
$r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' and channel_removed = 0 LIMIT 1",
dbesc($nick)
);

View file

@ -234,9 +234,11 @@ function oembed_fetch_url($embedurl){
if(preg_match('#\<iframe(.*?)src\=[\'\"](.*?)[\'\"]#',$j['html'],$matches)) {
$x = z_fetch_url($matches[2]);
$j['html'] = $x['body'];
$orig = $j['html'] = $x['body'];
}
logger('frame src: ' . $j['html'], LOGGER_DATA);
$j['html'] = purify_html($j['html'],$allow_position);
if($j['html'] != $orig) {
logger('oembed html was purified. original: ' . $orig . ' purified: ' . $j['html'], LOGGER_DEBUG, LOG_INFO);

View file

@ -822,6 +822,14 @@ function get_tags($s) {
}
}
// match bracket mentions
if(preg_match_all('/([@!]\{.*?\})/',$s,$match)) {
foreach($match[1] as $mtch) {
$ret[] = $mtch;
}
}
// Match full names against @tags including the space between first and last
// We will look these up afterward to see if they are full names or not recognisable.
@ -2025,22 +2033,40 @@ function item_post_type($item) {
function undo_post_tagging($s) {
$matches = null;
$x = null;
// undo tags and mentions
$cnt = preg_match_all('/([@#])(\!*)\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$s,$matches,PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
$s = str_replace($mtch[0], $mtch[1] . $mtch[2] . quote_tag($mtch[4]),$s);
if($mtch[1] === '@') {
$x = q("select xchan_addr, xchan_url from xchan where xchan_url = '%s' limit 1",
dbesc($mtch[3])
);
}
if($x) {
$s = str_replace($mtch[0], $mtch[1] . $mtch[2] . '{' . (($x[0]['xchan_addr']) ? $x[0]['xchan_addr'] : $x[0]['xchan_url']) . '}', $s);
}
else {
$s = str_replace($mtch[0], $mtch[1] . $mtch[2] . quote_tag($mtch[4]),$s);
}
}
}
// undo forum tags
$cnt = preg_match_all('/\!\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$s,$matches,PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
$s = str_replace($mtch[0], '!' . quote_tag($mtch[2]),$s);
$x = q("select xchan_addr, xchan_url from xchan where xchan_url = '%s' limit 1",
dbesc($mtch[1])
);
if($x) {
$s = str_replace($mtch[0], '!' . '{' . (($x[0]['xchan_addr']) ? $x[0]['xchan_addr'] : $x[0]['xchan_url']) . '}', $s);
}
else {
$s = str_replace($mtch[0], '!' . quote_tag($mtch[2]),$s);
}
}
}
return $s;
}
@ -2187,6 +2213,7 @@ function ids_to_querystr($arr,$idx = 'id',$quote = false) {
* @param $arr array
* @param $elm array key to extract from sub-array
* @param $delim string default ','
* @param $each filter function to apply to each element before evaluation, default is 'trim'.
* @returns string
*/
@ -2615,53 +2642,66 @@ function handle_tag($a, &$body, &$access_tag, &$str_tags, $profile_uid, $tag, $d
$forum = false;
$trailing_plus_name = false;
// @channel+ is a forum or network delivery tag
if(substr($newname,-1,1) === '+') {
$forum = true;
if(substr($name,0,1) === '{' && substr($name,-1,1) === '}') {
$newname = substr($name,1);
$newname = substr($newname,0,-1);
$r = q("select * from xchan where xchan_addr = '%s' or xchan_url = '%s' limit 1",
dbesc($newname),
dbesc($newname)
);
}
// Here we're looking for an address book entry as provided by the auto-completer
// of the form something+nnn where nnn is an abook_id or the first chars of xchan_hash
if(! $r) {
// @channel+ is a forum or network delivery tag
// If there's a +nnn in the string make sure there isn't a space preceding it
$t1 = strpos($newname,' ');
$t2 = strrpos($newname,'+');
if($t1 && $t2 && $t1 < $t2)
$t2 = 0;
if(($t2) && (! $diaspora)) {
//get the id
$tagcid = urldecode(substr($newname,$t2 + 1));
if(strrpos($tagcid,' '))
$tagcid = substr($tagcid,0,strrpos($tagcid,' '));
if(strlen($tagcid) < 16)
$abook_id = intval($tagcid);
//remove the next word from tag's name
if(strpos($name,' ')) {
$name = substr($name,0,strpos($name,' '));
if(substr($newname,-1,1) === '+') {
$forum = true;
$newname = substr($newname,0,-1);
}
if($abook_id) { // if there was an id
// select channel with that id from the logged in user's address book
$r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_id = %d AND abook_channel = %d LIMIT 1",
intval($abook_id),
intval($profile_uid)
);
}
else {
$r = q("SELECT * FROM xchan
WHERE xchan_hash like '%s%%' LIMIT 1",
dbesc($tagcid)
);
// Here we're looking for an address book entry as provided by the auto-completer
// of the form something+nnn where nnn is an abook_id or the first chars of xchan_hash
// If there's a +nnn in the string make sure there isn't a space preceding it
$t1 = strpos($newname,' ');
$t2 = strrpos($newname,'+');
if($t1 && $t2 && $t1 < $t2)
$t2 = 0;
if(($t2) && (! $diaspora)) {
//get the id
$tagcid = urldecode(substr($newname,$t2 + 1));
if(strrpos($tagcid,' '))
$tagcid = substr($tagcid,0,strrpos($tagcid,' '));
if(strlen($tagcid) < 16)
$abook_id = intval($tagcid);
//remove the next word from tag's name
if(strpos($name,' ')) {
$name = substr($name,0,strpos($name,' '));
}
if($abook_id) { // if there was an id
// select channel with that id from the logged in user's address book
$r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_id = %d AND abook_channel = %d LIMIT 1",
intval($abook_id),
intval($profile_uid)
);
}
else {
$r = q("SELECT * FROM xchan
WHERE xchan_hash like '%s%%' LIMIT 1",
dbesc($tagcid)
);
}
}
}
@ -3267,6 +3307,7 @@ function cleanup_bbcode($body) {
* First protect any url inside certain bbcode tags so we don't double link it.
*/
$body = preg_replace_callback('/\[code(.*?)\[\/(code)\]/ism','\red_escape_codeblock',$body);
$body = preg_replace_callback('/\[url(.*?)\[\/(url)\]/ism','\red_escape_codeblock',$body);
$body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','\red_escape_codeblock',$body);
@ -3296,7 +3337,6 @@ function cleanup_bbcode($body) {
$body = scale_external_images($body,false);
return $body;
}
@ -3344,6 +3384,9 @@ function featured_sort($a,$b) {
}
// Be aware that punify will convert domain names and pathnames
function punify($s) {
require_once('vendor/simplepie/simplepie/idn/idna_convert.class.php');
$x = new idna_convert(['encoding' => 'utf8']);
@ -3351,6 +3394,8 @@ function punify($s) {
}
// Be aware that unpunify will only convert domain names and not pathnames
function unpunify($s) {
require_once('vendor/simplepie/simplepie/idn/idna_convert.class.php');
$x = new idna_convert(['encoding' => 'utf8']);
@ -3358,3 +3403,18 @@ function unpunify($s) {
}
function unique_multidim_array($array, $key) {
$temp_array = array();
$i = 0;
$key_array = array();
foreach($array as $val) {
if (!in_array($val[$key], $key_array)) {
$key_array[$i] = $val[$key];
$temp_array[$i] = $val;
}
$i++;
}
return $temp_array;
}

View file

@ -60,7 +60,7 @@ function zid($s, $address = '') {
$url_match = true;
if ($mine && $myaddr && (! $url_match))
$zurl = $s . (($num_slashes >= 3) ? '' : '/') . $achar . 'zid=' . urlencode($myaddr);
$zurl = $s . (($num_slashes >= 3) ? '' : '/') . (($achar === '?') ? '?f=&' : '&') . 'zid=' . urlencode($myaddr);
else
$zurl = $s;
@ -103,6 +103,10 @@ function strip_zats($s) {
return preg_replace('/[\?&]zat=(.*?)(&|$)/ism','$2',$s);
}
function strip_escaped_zids($s) {
$x = preg_replace('/&amp\;zid=(.*?)(&|$)/ism','$2',$s);
return strip_query_param($x,'f');
}
function clean_query_string($s = '') {

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -15,11 +15,11 @@
#jot-title-wrap,
#jot-pagetitle-wrap,
#jot-category-wrap {
border-bottom: 1px solid #ccc;
border-bottom: 1px solid rgba(0, 0, 0, .2);
}
#jot-attachment-wrap {
border-top: 1px solid #ccc;
border-top: 1px solid rgba(0, 0, 0, .2);
}
#jot-title-wrap input,
@ -65,7 +65,7 @@
}
#profile-jot-submit-wrapper {
border-top: 1px solid #ccc;
border-top: 1px solid rgba(0, 0, 0, .2);
}
/* conversation */
@ -87,6 +87,23 @@
margin-left:10px;
}
.wall-item-photo-wrapper {
position: relative;
}
.wall-item-photo-caret {
position: absolute;
left: 3px;
bottom: 0px;
color: #fff;
text-shadow: 1px 1px 3px rgba(0, 0, 0, .5);
display: none;
}
.wall-item-photo-wrapper:hover .wall-item-photo-caret {
display: block;
}
.wall-item-divider {
margin: 5px;
}

View file

@ -41,6 +41,7 @@ li:hover .widget-nav-pills-icons {
/* notes */
#note-text {
border: 1px solid rgba(0,0,0,.125);
padding: 5px;
width: 100%;
resize: none;

View file

@ -8,20 +8,20 @@ function contact_search(term, callback, backend_url, type, extra_channels, spine
$(spinelement).show();
}
// Check if there is a cached result that contains the same information we would get with a full server-side search
var bt = backend_url+type;
if(!(bt in contact_search.cache)) contact_search.cache[bt] = {};
// var bt = backend_url+type;
// if(!(bt in contact_search.cache)) contact_search.cache[bt] = {};
var lterm = term.toLowerCase(); // Ignore case
for(var t in contact_search.cache[bt]) {
if(lterm.indexOf(t) >= 0) { // A more broad search has been performed already, so use those results
$(spinelement).hide();
// var lterm = term.toLowerCase(); // Ignore case
// for(var t in contact_search.cache[bt]) {
// if(lterm.indexOf(t) >= 0) { // A more broad search has been performed already, so use those results
// $(spinelement).hide();
// Filter old results locally
var matching = contact_search.cache[bt][t].filter(function (x) { return (x.name.toLowerCase().indexOf(lterm) >= 0 || (typeof x.nick !== 'undefined' && x.nick.toLowerCase().indexOf(lterm) >= 0)); }); // Need to check that nick exists because groups don't have one
matching.unshift({taggable:false, text: term, replace: term});
setTimeout(function() { callback(matching); } , 1); // Use "pseudo-thread" to avoid some problems
return;
}
}
// var matching = contact_search.cache[bt][t].filter(function (x) { return (x.name.toLowerCase().indexOf(lterm) >= 0 || (typeof x.nick !== 'undefined' && x.nick.toLowerCase().indexOf(lterm) >= 0)); }); // Need to check that nick exists because groups don't have one
// matching.unshift({taggable:false, text: term, replace: term});
// setTimeout(function() { callback(matching); } , 1); // Use "pseudo-thread" to avoid some problems
// return;
// }
// }
var postdata = {
start:0,
@ -41,9 +41,9 @@ function contact_search(term, callback, backend_url, type, extra_channels, spine
success: function(data){
// Cache results if we got them all (more information would not improve results)
// data.count represents the maximum number of items
if(data.items.length -1 < data.count) {
contact_search.cache[bt][lterm] = data.items;
}
// if(data.items.length -1 < data.count) {
// contact_search.cache[bt][lterm] = data.items;
// }
var items = data.items.slice(0);
items.unshift({taggable:false, text: term, replace: term});
callback(items);
@ -84,13 +84,8 @@ function editor_replace(item) {
}
// $2 ensures that prefix (@,@!) is preserved
var id = item.id;
// 16 chars of hash should be enough. Full hash could be used if it can be done in a visually appealing way.
// 16 chars is also the minimum length in the backend (otherwise it's interpreted as a local id).
if(id.length > 16)
id = item.id.substring(0,16);
return '$1$2' + item.nick.replace(' ', '') + '+' + id + ' ';
return '$1$2{' + item.link + '} ';
}
function basic_replace(item) {
@ -185,12 +180,17 @@ function string2bb(element) {
*/
(function( $ ) {
$.fn.editor_autocomplete = function(backend_url, extra_channels) {
if(! this.length)
return;
if (typeof extra_channels === 'undefined') extra_channels = false;
// Autocomplete contacts
contacts = {
match: /(^|\s)(@\!*)([^ \n]+)$/,
match: /(^|\s)(@\!*)([^ \n]{3,})$/,
index: 3,
cache: true,
search: function(term, callback) { contact_search(term, callback, backend_url, 'c', extra_channels, spinelement=false); },
replace: editor_replace,
template: contact_format
@ -198,8 +198,9 @@ function string2bb(element) {
// Autocomplete forums
forums = {
match: /(^|\s)(\!\!*)([^ \n]+)$/,
match: /(^|\s)(\!\!*)([^ \n]{3,})$/,
index: 3,
cache: true,
search: function(term, callback) { contact_search(term, callback, backend_url, 'f', extra_channels, spinelement=false); },
replace: editor_replace,
template: contact_format
@ -208,8 +209,9 @@ function string2bb(element) {
// Autocomplete hashtags
tags = {
match: /(^|\s)(\#)([^ \n]{2,})$/,
match: /(^|\s)(\#)([^ \n]{3,})$/,
index: 3,
cache: true,
search: function(term, callback) { $.getJSON('/hashtags/' + '$f=&t=' + term).done(function(data) { callback($.map(data, function(entry) { return entry.text.toLowerCase().indexOf(term.toLowerCase()) === 0 ? entry : null; })); }); },
replace: function(item) { return "$1$2" + item.text + ' '; },
context: function(text) { return text.toLowerCase(); },
@ -220,13 +222,23 @@ function string2bb(element) {
smilies = {
match: /(^|\s)(:[a-z_:]{2,})$/,
index: 2,
cache: true,
search: function(term, callback) { $.getJSON('/smilies/json').done(function(data) { callback($.map(data, function(entry) { return entry.text.indexOf(term) === 0 ? entry : null; })); }); },
//template: function(item) { return item.icon + item.text; },
replace: function(item) { return "$1" + item.text + ' '; },
template: smiley_format
};
this.attr('autocomplete','off');
this.textcomplete([contacts,forums,smilies,tags], {className:'acpopup', zIndex:1020});
var Textarea = Textcomplete.editors.Textarea;
$(this).each(function() {
var editor = new Textarea(this);
var textcomplete = new Textcomplete(editor);
textcomplete.register([contacts,forums,smilies,tags], {className:'acpopup', zIndex:1020});
});
};
})( jQuery );
@ -235,10 +247,15 @@ function string2bb(element) {
*/
(function( $ ) {
$.fn.search_autocomplete = function(backend_url) {
if(! this.length)
return;
// Autocomplete contacts
contacts = {
match: /(^@)([^\n]{3,})$/,
index: 2,
cache: true,
search: function(term, callback) { contact_search(term, callback, backend_url, 'x', [], spinelement='#nav-search-spinner'); },
replace: basic_replace,
template: contact_format,
@ -248,6 +265,7 @@ function string2bb(element) {
forums = {
match: /(^\!)([^\n]{3,})$/,
index: 2,
cache: true,
search: function(term, callback) { contact_search(term, callback, backend_url, 'f', [], spinelement='#nav-search-spinner'); },
replace: basic_replace,
template: contact_format
@ -257,6 +275,7 @@ function string2bb(element) {
tags = {
match: /(^\#)([^ \n]{3,})$/,
index: 2,
cache: true,
search: function(term, callback) { $.getJSON('/hashtags/' + '$f=&t=' + term).done(function(data) { callback($.map(data, function(entry) { return entry.text.toLowerCase().indexOf(term.toLowerCase()) === 0 ? entry : null; })); }); },
replace: function(item) { return "$1" + item.text + ' '; },
context: function(text) { return text.toLowerCase(); },
@ -264,65 +283,98 @@ function string2bb(element) {
};
this.attr('autocomplete', 'off');
var a = this.textcomplete([contacts,forums,tags], {className:'acpopup', maxCount:100, zIndex: 1020, appendTo:'nav'});
a.on('textComplete:select', function(e, value, strategy) { submit_form(this); });
var Textarea = Textcomplete.editors.Textarea;
$(this).each(function() {
var editor = new Textarea(this);
var textcomplete = new Textcomplete(editor);
textcomplete.register([contacts,forums,tags], {className:'acpopup', maxCount:100, zIndex: 1020, appendTo:'nav'});
});
this.on('select', function(e, value, strategy) { submit_form(this); });
};
})( jQuery );
(function( $ ) {
$.fn.contact_autocomplete = function(backend_url, typ, autosubmit, onselect) {
if(! this.length)
return;
if(typeof typ === 'undefined') typ = '';
if(typeof autosubmit === 'undefined') autosubmit = false;
// Autocomplete contacts
contacts = {
match: /(^)([^\n]+)$/,
match: /(^)([^\n]{3,})$/,
index: 2,
cache: true,
search: function(term, callback) { contact_search(term, callback, backend_url, typ,[], spinelement=false); },
replace: basic_replace,
template: contact_format,
};
this.attr('autocomplete','off');
var a = this.textcomplete([contacts], {className:'acpopup', zIndex:1020});
var Textarea = Textcomplete.editors.Textarea;
$(this).each(function() {
var editor = new Textarea(this);
var textcomplete = new Textcomplete(editor);
textcomplete.register([contacts], {className:'acpopup', zIndex:1020});
});
if(autosubmit)
a.on('textComplete:select', function(e,value,strategy) { submit_form(this); });
this.on('select', function(e,value,strategy) { submit_form(this); });
if(typeof onselect !== 'undefined')
a.on('textComplete:select', function(e, value, strategy) { onselect(value); });
this.on('select', function(e, value, strategy) { onselect(value); });
};
})( jQuery );
(function( $ ) {
$.fn.name_autocomplete = function(backend_url, typ, autosubmit, onselect) {
if(! this.length)
return;
if(typeof typ === 'undefined') typ = '';
if(typeof autosubmit === 'undefined') autosubmit = false;
// Autocomplete contacts
names = {
match: /(^)([^\n]+)$/,
match: /(^)([^\n]{3,})$/,
index: 2,
cache: true,
search: function(term, callback) { contact_search(term, callback, backend_url, typ,[], spinelement=false); },
replace: trim_replace,
template: contact_format,
};
this.attr('autocomplete','off');
var a = this.textcomplete([names], {className:'acpopup', zIndex:1020});
var Textarea = Textcomplete.editors.Textarea;
$(this).each(function() {
var editor = new Textarea(this);
var textcomplete = new Textcomplete(editor);
textcomplete.register([names], {className:'acpopup', zIndex:1020});
});
if(autosubmit)
a.on('textComplete:select', function(e,value,strategy) { submit_form(this); });
this.on('select', function(e,value,strategy) { submit_form(this); });
if(typeof onselect !== 'undefined')
a.on('textComplete:select', function(e, value, strategy) { onselect(value); });
this.on('select', function(e, value, strategy) { onselect(value); });
};
})( jQuery );
(function( $ ) {
$.fn.bbco_autocomplete = function(type) {
if(! this.length)
return;
if(type=='bbcode') {
var open_close_elements = ['bold', 'italic', 'underline', 'overline', 'strike', 'superscript', 'subscript', 'quote', 'code', 'open', 'spoiler', 'map', 'nobb', 'list', 'checklist', 'ul', 'ol', 'dl', 'li', 'table', 'tr', 'th', 'td', 'center', 'color', 'font', 'size', 'zrl', 'zmg', 'rpost', 'qr', 'observer', 'observer.language','embed', 'highlight', 'url', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
var open_elements = ['observer.baseurl', 'observer.address', 'observer.photo', 'observer.name', 'observer.webname', 'observer.url', '*', 'hr', ];
@ -380,11 +432,18 @@ function string2bb(element) {
};
this.attr('autocomplete','off');
var a = this.textcomplete([bbco], {className:'acpopup', zIndex:1020});
a.on('textComplete:select', function(e, value, strategy) { value; });
var Textarea = Textcomplete.editors.Textarea;
a.keypress(function(e){
$(this).each(function() {
var editor = new Textarea(this);
var textcomplete = new Textcomplete(editor);
textcomplete.register([bbco], {className:'acpopup', zIndex:1020});
});
this.on('select', function(e, value, strategy) { value; });
this.keypress(function(e){
if (e.keyCode == 13) {
var x = listNewLineAutocomplete(this.id);
if(x) {

View file

@ -15,9 +15,8 @@ head_add_js('jquery.js');
head_add_js('/library/justifiedGallery/jquery.justifiedGallery.min.js');
head_add_js('/library/sprintf.js/dist/sprintf.min.js');
//head_add_js('jquery.textinputs.js');
head_add_js('/library/textcomplete/textcomplete.min.js');
head_add_js('autocomplete.js');
head_add_js('/library/jquery-textcomplete/jquery.textcomplete.js');
head_add_js('/library/jquery.timeago.js');
head_add_js('/library/readmore.js/readmore.js');

View file

@ -1051,12 +1051,14 @@ img.mail-conv-sender-photo {
}
#profile-jot-wrapper {
background-color: rgba(254,254,254,1);
border: 1px solid #ccc;
background-color: rgba(254, 254, 254, 1);
border: 1px solid rgba(0, 0, 0, .2);
border-radius: $radius;
}
#jot-title,
#jot-pagetitle,
#profile-jot-text {
border-radius: $radius;
}
@ -1208,7 +1210,6 @@ img.mail-conv-sender-photo {
}
#note-text {
border: 1px solid #ccc;
border-radius: $radius;
}
@ -1303,8 +1304,7 @@ img.mail-conv-sender-photo {
}
.generic-content-wrapper {
border: 1px solid #ccc;
box-shadow: 0px 0px 5px 1px rgba(0,0,0,0.2);
border: 1px solid rgba(0, 0, 0, .2);
border-radius: $radius;
margin-bottom: 1.5rem;
}

View file

@ -1,7 +0,0 @@
.navbar-dark .navbar-toggler {
color: rgba(0,0,0,0.7);
}
#notifications-btn.text-white {
color: #777 !important;
}

View file

@ -0,0 +1,15 @@
.comment .wall-item-body {
padding-left: 42px;
}
.wall-item-content-wrapper.comment {
border-bottom: 1px solid #dee2e6;
}
.widget {
border: 1px solid #dee2e6;
}
#note-text {
border: 1px solid transparent;
}

View file

@ -0,0 +1,4 @@
.navbar-dark .navbar-toggler,
.navbar-dark .nav-link.active {
color: rgba(0,0,0,0.7) !important;
}

View file

@ -1,7 +0,0 @@
.comment .wall-item-body {
padding-left: 42px;
}
.wall-item-content-wrapper.comment {
border-bottom: 1px solid #ccc;
}

View file

@ -1,5 +1,4 @@
.generic-content-wrapper {
border: 1px solid #111;
background-color: transparent;
}
@ -148,7 +147,8 @@ option {
background-color:#111;
}
.modal-content {
.modal-content,
#notifications_wrapper {
background-color: #111;
}

View file

@ -31,6 +31,7 @@
<div class="wall-item-photo-wrapper{{if $item.owner_url}} wwfrom{{/if}} h-card p-author" id="wall-item-photo-wrapper-{{$item.id}}">
<img src="{{$item.thumb}}" class="fakelink wall-item-photo{{$item.sparkle}} u-photo p-name" id="wall-item-photo-{{$item.id}}" alt="{{$item.name}}" data-toggle="dropdown" />
{{if $item.thread_author_menu}}
<i class="fa fa-caret-down wall-item-photo-caret"></i>
<div class="dropdown-menu">
{{foreach $item.thread_author_menu as $mitem}}
<a class="dropdown-item" {{if $mitem.href}}href="{{$mitem.href}}"{{/if}} {{if $mitem.action}}onclick="{{$mitem.action}}"{{/if}} {{if $mitem.title}}title="{{$mitem.title}}"{{/if}} >{{$mitem.title}}</a>

View file

@ -31,6 +31,7 @@
<div class="wall-item-photo-wrapper{{if $item.owner_url}} wwfrom{{/if}} h-card p-author" id="wall-item-photo-wrapper-{{$item.id}}">
<img src="{{$item.thumb}}" class="fakelink wall-item-photo{{$item.sparkle}} u-photo p-name" id="wall-item-photo-{{$item.id}}" alt="{{$item.name}}" data-toggle="dropdown" /></a>
{{if $item.thread_author_menu}}
<i class="fa fa-caret-down wall-item-photo-caret"></i>
<div class="dropdown-menu">
{{foreach $item.thread_author_menu as $mitem}}
<a class="dropdown-item" {{if $mitem.href}}href="{{$mitem.href}}"{{/if}} {{if $mitem.action}}onclick="{{$mitem.action}}"{{/if}} {{if $mitem.title}}title="{{$mitem.title}}"{{/if}} >{{$mitem.title}}</a>

View file

@ -568,11 +568,14 @@ $( document ).on( "click", ".wall-item-delete-link,.page-delete-link,.layout-del
function postSaveChanges(action, type) {
if({{$auto_save_draft}}) {
var doctype = $('#jot-webpage').val();
var postid = '-' + doctype + '-' + $('#jot-postid').val();
if(action != 'clean') {
localStorage.setItem("post_title", $("#jot-title").val());
localStorage.setItem("post_body", $("#profile-jot-text").val());
localStorage.setItem("post_title" + postid, $("#jot-title").val());
localStorage.setItem("post_body" + postid, $("#profile-jot-text").val());
if($("#jot-category").length)
localStorage.setItem("post_category", $("#jot-category").val());
localStorage.setItem("post_category + postid", $("#jot-category").val());
}
if(action == 'start') {
@ -589,9 +592,9 @@ $( document ).on( "click", ".wall-item-delete-link,.page-delete-link,.layout-del
if(action == 'clean') {
clearTimeout(postSaveTimer);
postSaveTimer = null;
localStorage.removeItem("post_title");
localStorage.removeItem("post_body");
localStorage.removeItem("post_category");
localStorage.removeItem("post_title" + postid);
localStorage.removeItem("post_body" + postid);
localStorage.removeItem("post_category" + postid);
}
}
@ -602,9 +605,11 @@ $( document ).on( "click", ".wall-item-delete-link,.page-delete-link,.layout-del
var cleaned = false;
if({{$auto_save_draft}}) {
var postTitle = localStorage.getItem("post_title");
var postBody = localStorage.getItem("post_body");
var postCategory = (($("#jot-category").length) ? localStorage.getItem("post_category") : '');
var doctype = $('#jot-webpage').val();
var postid = '-' + doctype + '-' + $('#jot-postid').val();
var postTitle = localStorage.getItem("post_title" + postid);
var postBody = localStorage.getItem("post_body" + postid);
var postCategory = (($("#jot-category").length) ? localStorage.getItem("post_category" + postid) : '');
var openEditor = false;
if(postTitle) {

View file

@ -21,8 +21,8 @@
<input type="hidden" name="media_str" id="jot-media" value="" />
<input type="hidden" name="source" id="jot-source" value="{{$source}}" />
<input type="hidden" name="coord" id="jot-coord" value="" />
<input type="hidden" name="post_id" value="{{$post_id}}" />
<input type="hidden" name="webpage" value="{{$webpage}}" />
<input type="hidden" id="jot-postid" name="post_id" value="{{$post_id}}" />
<input type="hidden" id="jot-webpage" name="webpage" value="{{$webpage}}" />
<input type="hidden" name="preview" id="jot-preview" value="0" />
<input type="hidden" id="jot-consensus" name="consensus" value="{{if $consensus}}{{$consensus}}{{else}}0{{/if}}" />
<input type="hidden" id="jot-nocomment" name="nocomment" value="{{if $nocomment}}{{$nocomment}}{{else}}0{{/if}}" />