Version 4.1.2

This commit is contained in:
Neo committed 2025-12-19 05:32:19 -08:00
1 parent 3ba79295ee
commit 28bd025b35
1131 files changed
+63658 -20579

No files matched your search

+1 -1
View File
@@ -49,6 +49,6 @@ class _Application extends \IPS\Application
*/
protected function get__icon()
{
return 'file-text-o';
return 'file-text';
}
}
+6 -6
View File
@@ -1,16 +1,16 @@
{
"blogs": {
"blogs": {
"tab": "community",
"controller": "blogs",
"do": "",
"restriction": "blogs_manage"
},
"settings": {
"tab": "community",
"controller": "settings",
"do": "",
"restriction": "settings_manage"
},
"blogs": {
"tab": "community",
"controller": "blogs",
"do": "",
"restriction": "blogs_manage"
}
}
}
+4 -4
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<emails><template><template_app>blog</template_app><template_name>digests__item</template_name><template_content_html><![CDATA[<tr style='border-bottom: 1px solid #eeeeee'>
<td width='40' align='center' valign='top' class=' '>
<td dir='{dir}' width='40' align='center' valign='top' class=' '>
<img src='{$entry->author()->photo}' width='32' height='32' style='border: 1px solid #000; vertical-align: middle;'>
</td>
<td align='left'>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
{$email->language->addToStack("x_created_entry_in", FALSE, array( 'sprintf' => array( $entry->author()->name, $entry->container()->_title ) ) )}
</p>
@@ -27,10 +27,10 @@
</td>
</tr>]]></template_content_html><template_data>$entry, $email</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack("x_created_entry_in", FALSE, array( 'sprintf' => array( $entry->author()->name, $entry->container()->_title ) ) )}: {$entry->title} ({$entry->url()})
]]></template_content_plaintext></template><template><template_app>blog</template_app><template_name>digests__comment</template_name><template_content_html><![CDATA[<tr style='border-bottom: 1px solid #eeeeee'>
<td width='40' align='center' valign='top' class=' '>
<td dir='{dir}' width='40' align='center' valign='top' class=' '>
<img src='{$comment->author()->photo}' width='32' height='32' style='border: 1px solid #000; vertical-align: middle;'>
</td>
<td align='left'>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
{$email->language->addToStack("x_commented_entry", FALSE, array( 'sprintf' => array( $comment->author()->name ) ) )}
</p>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<javascript app="blog">
<file javascript_app="blog" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.list.js" javascript_type="controller" javascript_version="100045" javascript_position="1000050">/**
<file javascript_app="blog" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.list.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050">/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
+12 -4
View File
@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<language>
<app key="blog" version="100045">
<app key="blog" version="101012">
<word key="__app_blog" js="0">Blogs</word>
<word key="frontnavigation_blogs" js="0">Blogs</word>
<word key="__indefart_blog_entry_comment" js="0">a comment on a blog entry</word>
<word key="__indefart_blog_entry" js="0">a blog entry</word>
<word key="blog_entry_container" js="0">blog</word>
<word key="module__blog_blogs" js="0">Blogs</word>
<word key="menu__blog_blogs" js="0">Blogs</word>
<word key="menu__blog_blogs_settings" js="0">Settings</word>
@@ -112,8 +113,8 @@
<word key="unpublished" js="0">Unpublished</word>
<word key="blog_entry_locked_can_comment" js="0">This blog entry is locked, but your permissions allow you to add new comments.</word>
<word key="blog_entry_locked_cannot_comment" js="0">This blog entry is now closed to further comments.</word>
<word key="entry_posted" js="0">Entry posted</word>
<word key="entry_future_posted" js="0">Entry publishes on</word>
<word key="entry_posted" js="0">Entry posted by %s</word>
<word key="entry_future_posted" js="0">Entry by %s publishes on</word>
<word key="entry_images" js="0">Images</word>
<word key="blog_comments" js="0">{!#[1:comment][?:comments]}</word>
<word key="blog_entries" js="0">{!#[1:entry][?:entries]}</word>
@@ -124,7 +125,6 @@
<word key="my_blogs" js="0">My Blogs</word>
<word key="blogs_with_content" js="0">Blogs With Entries</word>
<word key="sort_last_edate" js="0">Last Entry</word>
<word key="sort_num_views" js="0">Views</word>
<word key="sort_rating_total" js="0">Rating</word>
<word key="from_the_blog" js="0">From the blog</word>
<word key="see_more_entries" js="0">See more entries from %s</word>
@@ -211,5 +211,13 @@
<word key="g_blog_allowownmod" js="0">Can moderate own blog entries?</word>
<word key="g_blog_allowownmod_desc" js="0">The user will be able to: edit comments and entries, delete comments and entries, and lock entries from further comments.</word>
<word key="g_blog_allowdelete" js="0">Can delete own blogs?</word>
<word key="block_blogCommentFeed" js="0">Blog Comments</word>
<word key="block_blogCommentFeed_desc" js="0">Display comments from blogs.</word>
<word key="block_blogs" js="0">Blogs</word>
<word key="block_blogs_desc" js="0">Display a list of blogs.</word>
<word key="widget_blog_last_date" js="0">Last entry posted</word>
<word key="widget__blog_edate" js="0">Last entry date</word>
<word key="widget__blog_count_entries" js="0">Number of entries</word>
<word key="widget__blog_count_comments" js="0">Number of comments</word>
</app>
</language>
+86 -110
View File
@@ -142,20 +142,6 @@
"values": [],
"zerofill": false
},
"blog_view_level": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "",
"length": 12,
"name": "blog_view_level",
"type": "VARCHAR",
"unsigned": false,
"values": [],
"zerofill": false
},
"blog_seo_name": {
"allow_null": true,
"auto_increment": false,
@@ -255,130 +241,130 @@
"zerofill": false
},
"blog_count_entries": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 11,
"name": "blog_count_entries",
"type": "INT",
"length": 11,
"decimals": null,
"values": [],
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
"values": [],
"zerofill": false
},
"blog_count_comments": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 11,
"name": "blog_count_comments",
"type": "INT",
"length": 11,
"decimals": null,
"values": [],
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
"values": [],
"zerofill": false
},
"blog_count_entries_hidden": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 11,
"name": "blog_count_entries_hidden",
"type": "INT",
"length": 11,
"decimals": null,
"values": [],
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
"values": [],
"zerofill": false
},
"blog_count_comments_hidden": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 11,
"name": "blog_count_comments_hidden",
"type": "INT",
"length": 11,
"decimals": null,
"values": [],
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
"values": [],
"zerofill": false
},
"blog_rating_average": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 11,
"name": "blog_rating_average",
"type": "INT",
"length": 11,
"decimals": null,
"values": [],
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
"values": [],
"zerofill": false
},
"blog_cover_photo": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 0,
"name": "blog_cover_photo",
"type": "TEXT",
"length": null,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
"values": [],
"zerofill": false
},
"blog_cover_photo_offset": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 10,
"name": "blog_cover_photo_offset",
"type": "INT",
"length": 10,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
"values": [],
"zerofill": false
},
"blog_social_group": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "The social group ID, is this is a private blog",
"decimals": null,
"default": null,
"length": 10,
"name": "blog_social_group",
"type": "INT",
"length": 10,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "The social group ID, is this is a private blog",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
"values": [],
"zerofill": false
},
"blog_count_entries_future": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 10,
"name": "blog_count_entries_future",
"type": "INT",
"length": 10,
"decimals": null,
"values": [],
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
"values": [],
"zerofill": false
}
},
"indexes": {
@@ -406,22 +392,10 @@
"type": "key",
"name": "blog_grabber",
"length": [
null,
null
],
"columns": [
"blog_disabled",
"blog_view_level"
]
},
"blog_view_level": {
"type": "key",
"name": "blog_view_level",
"length": [
null
],
"columns": [
"blog_view_level"
"blog_disabled"
]
},
"blog_pinned": {
@@ -459,7 +433,7 @@
"name": "auth_user",
"length": [
null,
253
190
],
"columns": [
"blog_owner_only",
@@ -482,7 +456,9 @@
"blog_last_edate"
]
}
}
},
"collation": "utf8mb4_unicode_ci",
"engine": "InnoDB"
},
"blog_entries": {
"name": "blog_entries",
+254 -116
View File
@@ -149,12 +149,6 @@
<div>
<strong class='ipsType_minorHeading'>{lang="latest_entry"}</strong><br>
<h3 class='ipsType_reset ipsType_sectionHead ipsType_blendLinks'>
<a href='{$blog->latestEntry()->url()}' title='{lang="view_this_entry" sprintf="$blog->latestEntry()->name"}'>
{{if $blog->latestEntry()->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="unread_blog"}"><i class="fa fa-circle"></i></span>
{{endif}}
{wordbreak="$blog->latestEntry()->name"}
</a>
{{if $blog->latestEntry()->locked()}}<i class='fa fa-lock'></i> {{endif}}{$blog->latestEntry()->caption}
{{if $blog->latestEntry()->isFutureDate() || $blog->latestEntry()->mapped('pinned') || $blog->latestEntry()->mapped('featured') || $blog->latestEntry()->hidden() === -1 || $blog->latestEntry()->hidden() === 1 || $blog->latestEntry()->status === 'draft'}}
{{if $blog->latestEntry()->isFutureDate()}}
@@ -174,13 +168,20 @@
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
<a href='{$blog->latestEntry()->url()}' title='{lang="view_this_entry" sprintf="$blog->latestEntry()->name"}'>
{{if $blog->latestEntry()->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="unread_blog"}"><i class="fa fa-circle"></i></span>
{{endif}}
{wordbreak="$blog->latestEntry()->name"}
</a>
</h3>
{{if !( $blog->owner() instanceof \IPS\Member )}}
<p class='ipsType_medium ipsType_reset ipsType_light'>{lang="byline" htmlsprintf="trim( $blog->latestEntry()->author()->link() )"} {datetime="$blog->latestEntry()->date"}</p>
{{endif}}
</div>
</div>
<div class='ipsType_medium ipsType_richText ipsSpacer_both cBlogInfo_content'>
<div class='ipsType_medium ipsType_richText ipsSpacer_both cBlogInfo_content' data-controller="core.front.core.lightboxedImages">
{$blog->latestEntry()->content()|raw}
</div>
<ul class='ipsList_inline'>
@@ -339,40 +340,6 @@
{template="blogViewMedium" group="view" app="blog" params="$entry, $table, FALSE"}
</li>
{{endforeach}}]]></template>
<template template_group="global" template_name="snippet" template_data="$activity, $type='activity'" template_location="front" template_app="blog"><![CDATA[
{{if $activity instanceof \IPS\calendar\Event\Comment or $activity instanceof \IPS\calendar\Event\Review}}
{{$item = $activity->item();}}
{{else}}
{{$item = $activity;}}
{{endif}}
{{if $activity instanceof \IPS\blog\Entry\Comment}}
{{if mb_strlen( trim( strip_tags( $activity->truncated() ) ) ) }}
<div class='cSearchActivity_info ipsContained'>
<div class='ipsType_medium ipsType_richText ipsContained ipsSpacer_bottom' data-ipsTruncate data-ipsTruncate-size='3 lines' data-ipsTruncate-type='remove'>
{$activity->truncated()|raw}
</div>
{{if $type != 'search'}}
<ul class='ipsList_inline ipsType_light'>
<li>{template="reputationMini" group="global" app="core" params="$activity, '', NULL, TRUE"}</li>
</ul>
{{endif}}
</div>
{{endif}}
{{else}}
<div class='cSearchActivity_info ipsContained'>
{{if $type != 'search'}}<a href='{$activity->url()}' class='ipsType_normal ipsType_break'>{$item->mapped('title')}</a>{{endif}}
<div class='ipsType_medium ipsType_richText ipsContained ipsSpacer_both ipsSpacer_half' data-ipsTruncate data-ipsTruncate-size='3 lines' data-ipsTruncate-type='remove'>
{$item->truncated()|raw}
</div>
<ul class='ipsList_inline ipsType_light'>
<li>{lang="num_comments" pluralize="$item->count_comments"}</li>
{{if $type != 'search' and $item instanceof \IPS\Content\Reputation and settings.reputation_enabled}}
<li>{template="reputationMini" group="global" app="core" params="$item, '', NULL, TRUE"}</li>
{{endif}}
</ul>
</div>
{{endif}}]]></template>
<template template_group="livesearch" template_name="blog" template_data="$blog" template_location="admin" template_app="blog"><![CDATA[<li class='ipsPad_half ipsClearfix' data-role='result'>
<a href='{url="app=blog&module=blogs&controller=blogs&do=form&id="}{$blog->id}' class='ipsPos_left'>{$blog->_title}</a>
</li>
@@ -402,7 +369,7 @@
{{endif}}
{{if count( $elements ) > 1}}
<h2 class='ipsType_sectionTitle ipsType_reset'>{lang="entry_information"}</h2>
<div class='ipsTabs ipsTabs_contained ipsClearfix ipsJS_show' id='tabs_{$id}' data-ipsTabBar data-ipsTabBar-contentArea='#ipsTabs_content_{$id}'>
<div class='ipsTabs ipsClearfix ipsJS_show' id='tabs_{$id}' data-ipsTabBar data-ipsTabBar-contentArea='#ipsTabs_content_{$id}'>
<a href='#tabs_{$id}' data-action='expandTabs'><i class='fa fa-caret-down'></i></a>
<ul role='tablist'>
{{foreach $elements as $name => $content}}
@@ -414,7 +381,7 @@
{{endforeach}}
</ul>
</div>
<div id='ipsTabs_content_{$id}' class='ipsTabs_panels ipsTabs_contained'>
<div id='ipsTabs_content_{$id}' class='ipsTabs_panels'>
{{foreach $elements as $name => $contents}}
<div id='ipsTabs_tabs_{$id}_{$id}_tab_{$name}_panel' class="ipsTabs_panel ipsPad" aria-labelledby="{$id}_tab_{$name}" aria-hidden="false">
<ul class='ipsForm ipsForm_vertical'>
@@ -644,20 +611,11 @@
{{endif}}
</div>]]></template>
<template template_group="view" template_name="blogViewLarge" template_data="$entry, $table, $first = FALSE" template_location="front" template_app="blog"><![CDATA[
<article class='cBlogView_entry {{if $entry->hidden()}}ipsModerated{{endif}}'>
<article class='cBlogView_entry ipsContained {{if $entry->hidden()}}ipsModerated{{endif}}' data-controller="core.front.core.lightboxedImages">
<header class='ipsPhotoPanel ipsPhotoPanel_notPhone ipsPhotoPanel_small ipsSpacer_bottom'>
{template="userPhoto" app="core" params="$entry->author()" group="global"}
<div>
<h2 class='ipsType_pageTitle'>
{{if $entry->prefix()}}
{template="prefix" group="global" app="core" params="$entry->prefix( TRUE ), $entry->prefix()"}
{{endif}}
<a href="{$entry->url()}" title="{lang="read_more_about" sprintf="$entry->name"}" {{if $entry->canEdit()}}data-role="editableTitle"{{endif}}>
{{if $entry->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="unread_blog"}"><i class="fa fa-circle"></i></span>
{{endif}}
{{if $entry->canEdit()}}<span data-role="editableTitle">{wordbreak="$entry->name"}</span>{{else}}{wordbreak="$entry->name"}{{endif}}
</a>
{{if $entry->locked()}}<i class='fa fa-lock'></i> {{endif}}{$entry->caption}
{{if $entry->isFutureDate() || $entry->mapped('pinned') || $entry->mapped('featured') || $entry->hidden() === -1 || $entry->hidden() === 1 || $entry->status === 'draft'}}
{{if $entry->isFutureDate() and $entry->status !== 'draft'}}
@@ -677,8 +635,18 @@
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
{{if $entry->prefix()}}
{template="prefix" group="global" app="core" params="$entry->prefix( TRUE ), $entry->prefix()"}
{{endif}}
<a href="{$entry->url()}" class='ipsType_blendLinks' title="{lang="read_more_about" sprintf="$entry->name"}" {{if $entry->canEdit()}}data-role="editableTitle"{{endif}}>
{{if $entry->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="unread_blog"}"><i class="fa fa-circle"></i></span>
{{endif}}
{{if $entry->canEdit()}}<span data-role="editableTitle">{wordbreak="$entry->name"}</span>{{else}}{wordbreak="$entry->name"}{{endif}}
</a>
</h2>
<p class='ipsType_light ipsType_reset'>
<p class='ipsType_light ipsType_reset ipsType_blendLinks'>
{lang="byline" htmlsprintf="$entry->author()->link()"}{datetime="$entry->date"}
</p>
</div>
@@ -687,11 +655,13 @@
<section class='ipsType_normal ipsType_richText ipsType_break ipsSpacer_both' data-ipsTruncate {{if $first}}data-ipsTruncate-size='20 lines'{{else}}data-ipsTruncate-size='7 lines'{{endif}}>
{$entry->content|raw}
</section>
{{if count( $entry->tags() )}}
{template="tags" group="global" app="core" params="$entry->tags()"}
{{if count( $entry->tags() )}}
<div class='ipsSpacer_top'>
{template="tags" group="global" app="core" params="$entry->tags()"}
</div>
{{endif}}
<ul class='ipsList_inline'>
<ul class='ipsList_inline ipsSpacer_top'>
{{if $table->canModerate()}}
<li class='ipsPos_left'>
{{$idField = $entry::$databaseColumnId;}}
@@ -702,25 +672,16 @@
{{if \IPS\Settings::i()->blog_enable_rating}}
<li>{template="rating" app="core" params="'small', $entry->averageRating()" group="global"}</li>
{{endif}}
<li><a href='{$entry->url()}#comments' title='{lang="view_comments"}'><i class='fa fa-comment'></i> {lang="num_comments" pluralize="$entry->num_comments"}</a></li>
<li><a href='{$entry->url()}#comments' title='{lang="view_comments"}' class='ipsType_light'>{lang="num_comments" pluralize="$entry->num_comments"}</a></li>
<li class='ipsType_light'>{lang="num_views_with_number" pluralize="$entry->views"}</li>
</ul>
</article>]]></template>
<template template_group="view" template_name="blogViewMedium" template_data="$entry, $table" template_location="front" template_app="blog"><![CDATA[
<article class='cBlogView_entry {{if $entry->hidden()}}ipsModerated{{endif}}'>
<article class='cBlogView_entry ipsContained {{if $entry->hidden()}}ipsModerated{{endif}}' data-controller="core.front.core.lightboxedImages">
<header class='ipsPhotoPanel ipsPhotoPanel_mini ipsPhotoPanel_notPhone'>
{template="userPhoto" app="core" params="$entry->author(), 'mini'" group="global"}
<div>
<h2 class='ipsType_sectionHead ipsType_blendLinks ipsTruncate ipsTruncate_line'>
{{if $entry->prefix()}}
{template="prefix" group="global" app="core" params="$entry->prefix( TRUE ), $entry->prefix()"}
{{endif}}
<a href="{$entry->url()}" title="{lang="read_more_about" sprintf="$entry->name"}" {{if $entry->canEdit()}}data-role="editableTitle"{{endif}}>
{{if $entry->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="unread_blog"}"><i class="fa fa-circle"></i></span>
{{endif}}
{wordbreak="$entry->name"}
</a>
{{if $entry->isFutureDate() || $entry->mapped('pinned') || $entry->mapped('featured') || $entry->hidden() === -1 || $entry->hidden() === 1}}
{{if $entry->isFutureDate() and $entry->status !== 'draft'}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$entry->futureDateBlurb()}'><i class='fa fa-clock-o'></i></span>
@@ -734,8 +695,18 @@
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
{{if $entry->prefix()}}
{template="prefix" group="global" app="core" params="$entry->prefix( TRUE ), $entry->prefix()"}
{{endif}}
<a href="{$entry->url()}" title="{lang="read_more_about" sprintf="$entry->name"}" {{if $entry->canEdit()}}data-role="editableTitle"{{endif}}>
{{if $entry->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="unread_blog"}"><i class="fa fa-circle"></i></span>
{{endif}}
{wordbreak="$entry->name"}
</a>
</h2>
<p class='ipsType_light ipsType_reset'>
<p class='ipsType_light ipsType_reset ipsType_blendLinks'>
{lang="byline" htmlsprintf="$entry->author()->link()"}{datetime="$entry->date"}
</p>
{{if \IPS\Settings::i()->blog_enable_rating}}
@@ -756,46 +727,15 @@
</li>
{{endif}}
<li><strong><a href='{$entry->url()}' title="{lang="read_more_about" sprintf="$entry->name"}">{lang="read_more"}</a></strong></li>
<li><a href='{$entry->url()}#comments' title='{lang="view_comments"}'><i class='fa fa-comment'></i> {lang="num_comments" pluralize="$entry->num_comments"}</a></li>
<li><a href='{$entry->url()}#comments' title='{lang="view_comments"}' class='ipsType_light'>{lang="num_comments" pluralize="$entry->num_comments"}</a></li>
<li class='ipsType_light'>{lang="num_views_with_number" pluralize="$entry->views"}</li>
</ul>
</article>]]></template>
<template template_group="view" template_name="blogViewSmall" template_data="$entry, $table" template_location="front" template_app="blog"><![CDATA[
<li class='cBlogView_entry'>
<div class='ipsPhotoPanel ipsPhotoPanel_tiny ipsPhotoPanel_notPhone'>
{template="userPhoto" app="core" params="$entry->author(), 'tiny'" group="global"}
<div>
{{if $entry->prefix()}}
{template="prefix" group="global" app="core" params="$entry->prefix( TRUE ), $entry->prefix()"}
{{endif}}
<a href="{$entry->url()}" title="{lang="read_more_about" sprintf="$entry->name"}" class='ipsType_large ipsType_blendLinks' {{if $entry->canEdit()}}data-role="editableTitle"{{endif}}>
{{if $entry->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="unread_blog"}"><i class="fa fa-circle"></i></span>
{{endif}}
{wordbreak="$entry->name"}
</a><br>
<p class='ipsType_light ipsType_reset'>
{lang="byline" htmlsprintf="$entry->author()->link()"}{datetime="$entry->date"}
</p>
<ul class='ipsList_inline'>
{{if $table->canModerate()}}
<li class='ipsPos_left'>
{{$idField = $entry::$databaseColumnId;}}
<input type='checkbox' data-role='moderation' name="moderate[{$entry->$idField}]" data-actions="{expression="implode( ' ', $table->multimodActions( $entry ) )"}" data-state='{{if $entry->tableStates()}}{$entry->tableStates()}{{endif}}'>
</li>
{{endif}}
<li>
<a href='{$entry->url()}#comments' title='{lang="view_comments"}'><i class='fa fa-comment'></i> {lang="num_comments" pluralize="$entry->num_comments"}</a>
</li>
</ul>
</div>
</div>
</li>]]></template>
<template template_group="view" template_name="comments" template_data="$entry" template_location="front" template_app="blog"><![CDATA[<div class='ipsBox'>
<div data-controller='core.front.core.commentFeed' data-baseURL='{$entry->url()}' data-feedID='entry-{$entry->id}' id='comments'>
<div data-controller='core.front.core.commentFeed' {{if settings.auto_polling_enabled}}data-autoPoll{{endif}} data-baseURL='{$entry->url()}' data-feedID='entry-{$entry->id}' id='comments'>
<div class='ipsPad'>
<h2 class='ipsType_sectionHead ipsSpacer_bottom' data-role="comment_count">{lang="num_comments_uc" pluralize="$entry->num_comments"}</h2>
<h2 class='ipsType_sectionHead' data-role="comment_count">{lang="num_comments_uc" pluralize="$entry->num_comments"}</h2>
<hr class='ipsHr'>
{{if $entry->commentPageCount() > 1}}
{$entry->commentPagination()|raw}
<br><br>
@@ -851,13 +791,10 @@
{{endif}}
<a href='{$blog->url()}' title='{lang="go_to_blog" sprintf="$blog->_title"}' class='ipsType_blendLinks'>
<h1 class='ipsType_pageTitle ipsType_break ipsTruncate ipsTruncate_line'>
{{if $blog->pinned && \IPS\Request::i()->module != 'view'}}
{{if $blog->pinned}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{$blog->_title}
{{if $blog->pinned && \IPS\Request::i()->module == 'view'}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
</h1>
</a>
<p class='ipsType_normal ipsType_reset ipsType_blendLinks'>
@@ -880,11 +817,6 @@
<article class='ipsBox ipsPad ipsSpacer_top'>
<header>
<h1 class='ipsType_pageTitle ipsType_largeTitle ipsType_break'>
{{if $entry->prefix()}}
{template="prefix" group="global" app="core" params="$entry->prefix( TRUE ), $entry->prefix()"}
{{endif}}
{wordbreak="$entry->name"}
{{if $entry->locked()}}<i class='fa fa-lock'></i> {{endif}}{$entry->caption}
{{if $entry->isFutureDate() || $entry->mapped('pinned') || $entry->mapped('featured') || $entry->hidden() === -1 || $entry->hidden() === 1 || $entry->status === 'draft'}}
{{if $entry->isFutureDate() and $entry->status !== 'draft'}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$entry->futureDateBlurb()}'><i class='fa fa-clock-o'></i></span>
@@ -903,6 +835,12 @@
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
{{if $entry->prefix()}}
{template="prefix" group="global" app="core" params="$entry->prefix( TRUE ), $entry->prefix()"}
{{endif}}
{wordbreak="$entry->name"}
{{if $entry->locked()}}<i class='fa fa-lock'></i> {{endif}}{$entry->caption}
</h1>
<div class='ipsPhotoPanel ipsPhotoPanel_tiny ipsSpacer_top'>
@@ -911,7 +849,7 @@
</div>
{template="userPhoto" app="core" params="$entry->author(), 'tiny'" group="global"}
<div>
<p class='ipsType_light ipsType_reset'>{{if $entry->date > time()}}{lang="entry_future_posted"}{{else}}{lang="entry_posted"}{{endif}} {datetime="$entry->date"}</p>
<p class='ipsType_light ipsType_reset ipsType_blendLinks'>{{if $entry->date > time()}}{lang="entry_future_posted" htmlsprintf="$entry->author()->link()"}{{else}}{lang="entry_posted" htmlsprintf="$entry->author()->link()"}{{endif}} &middot; {datetime="$entry->date"}</p>
<p class='ipsType_light ipsType_reset'>{lang="num_views_with_number" pluralize="$entry->views"}</p>
{{if \IPS\Settings::i()->blog_enable_rating}}
{$entry->rating()|raw}
@@ -1135,6 +1073,206 @@
<div class='ipsResponsive_showPhone ipsResponsive_block ipsSpacer_top'>
{template="follow" app="core" group="global" params="'blog', 'blog', $blog->_id, \IPS\blog\Entry::containerFollowerCount( $blog )"}
</div>]]></template>
<template template_group="widgets" template_name="blogCommentFeed" template_data="$comments, $title, $orientation='vertical'" template_location="front" template_app="blog"><![CDATA[{{if !empty( $comments ) }}
<h3 class='ipsType_reset ipsWidget_title'>{$title}</h3>
{{if $orientation == 'vertical'}}
<div class='ipsWidget_inner ipsPad_half'>
<ul class='ipsDataList ipsDataList_reducedSpacing'>
{{foreach $comments as $comment}}
<li class='ipsDataItem'>
<div class='ipsDataItem_icon ipsPos_top'>
{template="userPhoto" group="global" app="core" params="$comment->author(), 'tiny'"}
</div>
<div class='ipsDataItem_main'>
<a href="{$comment->url()}" class='ipsType_medium ipsType_break'>{wordbreak="$comment->item()->name"}</a><br>
<p class='ipsType_reset ipsType_medium ipsType_light ipsType_blendLinks'>{lang="byline_nodate" htmlsprintf="$comment->author()->link()"} &middot; <a href="{$comment->url()}" class='ipsDataItem_title ipsType_break ipsType_blendLinks'>{$comment->dateLine()|raw}</a></p>
<div class='ipsType_medium ipsType_textBlock ipsType_richText ipsType_break ipsContained ipsSpacer_top ipsSpacer_half' data-ipsTruncate data-ipsTruncate-type='remove' data-ipsTruncate-size='{{if $orientation == 'vertical'}}6 lines{{else}}2 lines{{endif}}'>
{$comment->truncated( true )|raw}
</div>
</div>
</li>
{{endforeach}}
</ul>
</div>
{{else}}
<div class='ipsWidget_inner'>
<ul class='ipsDataList'>
{{foreach $comments as $comment}}
<li class='ipsDataItem ipsClearfix'>
<div class='ipsComment_header ipsPhotoPanel ipsPhotoPanel_mini'>
{template="userPhoto" app="core" group="global" params="$comment->author(), 'mini', $comment->warningRef()"}
<div>
<p class='ipsPos_right ipsType_reset ipsType_blendLinks'>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->id ) )}' data-ipsTooltip title='{lang="share_this_comment"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elShareComment_{$comment->id}'><i class='fa fa-share-alt'></i></a>
</p>
<h3 class='ipsComment_author ipsType_blendLinks'>
<strong class='ipsType_normal'>{template="userLink" app="core" group="global" params="$comment->author(), $comment->warningRef()"}</strong>
{template="reputationBadge" group="global" app="core" params="$comment->author()"}
</h3>
<p class='ipsComment_meta ipsType_light ipsType_medium'>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->id ) )}' class='ipsType_blendLinks' title='{lang="share_this_comment"}'>{$comment->dateLine()|raw}</a>
{{if $comment->editLine()}}
({lang="edited_lc"})
{{endif}}
{{if $comment->hidden()}}
&middot; {$comment->hiddenBlurb()}
{{endif}}
{{if $comment instanceof \IPS\Content\ReportCenter and !\IPS\Member::loggedIn()->group['gbw_no_report'] and $comment->hidden() !== 1 }}
&middot; <a href='{$comment->url('report')}' data-ipsDialog data-ipsDialog-remoteSubmit data-ipsDialog-size='medium' data-ipsDialog-flashMessage='{lang="report_submit_success"}' data-ipsDialog-title="{lang="report"}" data-action='reportComment' title='{lang="report_content"}'>{lang="report"}</a>
{{endif}}
</p>
{{if member.modPermission('mod_see_warn') and $comment->warning}}
{template="commentWarned" group="global" app="core" params="$comment"}
{{endif}}
</div>
</div>
<div class='ipsPad ipsClearfix'>
{{if in_array( 'IPS\Content\Reputation', class_implements( $comment ) ) and settings.reputation_highlight and $comment->reputation() >= settings.reputation_highlight}}
<strong class='ipsComment_popularFlag' data-ipsTooltip title='{lang="this_is_a_popular_comment"}'><i class='fa fa-star'></i></strong>
{{endif}}
<a href="{$comment->url()}" class='ipsDataItem_title ipsType_break'>{wordbreak="$comment->item()->name"}</a><br>
<div data-role='commentContent' class='ipsType_normal ipsType_richText ipsType_break ipsContained' data-controller='core.front.core.lightboxedImages'>
{{if $comment->hidden() === 1 && $comment->author()->member_id == \IPS\Member::loggedIn()->member_id}}
<strong class='ipsType_medium ipsType_warning'><i class='fa fa-info-circle'></i> {lang="comment_awaiting_approval"}</strong>
{{endif}}
{$comment->content()|raw}
{{if $comment->editLine()}}
{$comment->editLine()|raw}
{{endif}}
</div>
{{if $comment->hidden() !== 1 && $comment instanceof \IPS\Content\Reputation and settings.reputation_enabled}}
{template="reputation" group="global" app="core" params="$comment, 'ipsPos_right ipsResponsive_noFloat'"}
{{endif}}
</div>
</li>
{{endforeach}}
</ul>
</div>
{{endif}}
{{endif}}
]]></template>
<template template_group="widgets" template_name="blogs" template_data="$blogs, $title, $orientation='vertical'" template_location="front" template_app="blog"><![CDATA[<h3 class='ipsType_reset ipsWidget_title'>{$title}</h3>
{{if $orientation == 'vertical'}}
<div class='ipsPad_half ipsWidget_inner'>
<ul class='ipsDataList ipsDataList_reducedSpacing'>
{{foreach $blogs as $blog}}
<li class='ipsDataItem'>
<div class='ipsColumns ipsColumns_collapsePhone'>
<h4 class='ipsType_large ipsType_reset'>{$blog->_title}</h4>
<div>
<ul class='ipsGrid'>
<li class='ipsGrid_span4'><strong class='ipsType_normal'>{$blog->_items}</strong><br>{lang="blog_entries" pluralize="$blog->_items"}</li>
<li class='ipsGrid_span4'><strong class='ipsType_normal'>{$blog->_comments}</strong><br>{lang="blog_comments" pluralize="$blog->_comments"}</li>
<li class='ipsGrid_span4'><strong class='ipsType_normal'>{$blog->num_views}</strong><br>{lang="blog_views" pluralize="$blog->num_views"}</li>
</ul>
</div>
</div>
</li>
{{endforeach}}
</ul>
</div>
{{else}}
<ol class="ipsDataList ipsClear cBlogList ipsAreaBackground ipsDataList_large" data-role="tableRows" itemscope="" itemtype="http://schema.org/ItemList">
{{foreach $blogs as $blog}}
<li class='ipsDataItem ipsAreaBackground_reset'>
<div class='ipsColumns ipsColumns_collapsePhone'>
<div class='ipsColumn ipsColumn_veryWide cBlogInfo ipsAreaBackground_light'>
{$blog->coverPhoto()|raw}
<div class='ipsPad'>
<ul class='ipsGrid'>
<li class='ipsGrid_span4'><strong class='ipsType_normal'>{$blog->_items}</strong><br>{lang="blog_entries" pluralize="$blog->_items"}</li>
<li class='ipsGrid_span4'><strong class='ipsType_normal'>{$blog->_comments}</strong><br>{lang="blog_comments" pluralize="$blog->_comments"}</li>
<li class='ipsGrid_span4'><strong class='ipsType_normal'>{$blog->num_views}</strong><br>{lang="blog_views" pluralize="$blog->num_views"}</li>
</ul>
{{if count( $blog->_recentEntries )}}
<h4 class='ipsType_minorHeading'>{lang="recent_entries"}</h4>
<ul class='ipsDataList ipsDataList_reducedSpacing ipsType_medium ipsList_reset ipsType_light'>
{{foreach $blog->_recentEntries as $entry}}
<li class='ipsDataItem'>
<div class='ipsDataItem_main'>
{{if $entry->unread()}}
<a href='{$entry->url()}' title='{lang="view_this_entry" sprintf="$entry->name"}' class=''>
<span class='ipsItemStatus ipsItemStatus_tiny'><i class='fa fa-circle'></i></span>
</a>
{{endif}}
<a href='{$entry->url()}' title='{lang="view_this_entry" sprintf="$entry->name"}' class='ipsType_break'>
{wordbreak="$entry->name"}
</a>
</div>
</li>
{{endforeach}}
</ul>
{{endif}}
</div>
</div>
<div class='ipsColumn ipsColumn_fluid ipsPad'>
{{if $blog->latestEntry()}}
<div class='ipsPhotoPanel ipsPhotoPanel_mini'>
{template="userPhoto" app="core" params="$blog->latestEntry()->author(), 'mini'" group="global"}
<div>
<strong class='ipsType_minorHeading'>{lang="latest_entry"}</strong><br>
<h3 class='ipsType_reset ipsType_sectionHead ipsType_blendLinks'>
<a href='{$blog->latestEntry()->url()}' title='{lang="view_this_entry" sprintf="$blog->latestEntry()->name"}'>
{{if $blog->latestEntry()->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="unread_blog"}"><i class="fa fa-circle"></i></span>
{{endif}}
{wordbreak="$blog->latestEntry()->name"}
</a>
{{if $blog->latestEntry()->locked()}}<i class='fa fa-lock'></i> {{endif}}{$blog->latestEntry()->caption}
{{if $blog->latestEntry()->isFutureDate() || $blog->latestEntry()->mapped('pinned') || $blog->latestEntry()->mapped('featured') || $blog->latestEntry()->hidden() === -1 || $blog->latestEntry()->hidden() === 1 || $blog->latestEntry()->status === 'draft'}}
{{if $blog->latestEntry()->isFutureDate()}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$blog->latestEntry()->futureDateBlurb()}'><i class='fa fa-clock-o'></i></span>
{{elseif $blog->latestEntry()->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$blog->latestEntry()->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $blog->latestEntry()->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $blog->latestEntry()->status === 'draft'}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{lang="unpublished"}'><i class='fa fa-pencil-square-o'></i></span>
{{endif}}
{{if $blog->latestEntry()->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $blog->latestEntry()->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
</h3>
{{if !( $blog->owner() instanceof \IPS\Member )}}
<p class='ipsType_medium ipsType_reset ipsType_light'>{lang="byline" htmlsprintf="trim( $blog->latestEntry()->author()->link() )"} {datetime="$blog->latestEntry()->date"}</p>
{{endif}}
</div>
</div>
<div class='ipsType_medium ipsType_richText ipsSpacer_both cBlogInfo_content'>
{$blog->latestEntry()->content()|raw}
</div>
<ul class='ipsList_inline'>
<li>
<strong><a href='{$blog->latestEntry()->url()}' title='{lang="read_more_entry"}'>{lang="read_more"}</a></strong>
</li>
{{if \IPS\Settings::i()->blog_enable_rating}}
<li>{template="rating" app="core" params="'small', $blog->latestEntry()->averageRating()" group="global"}</li>
{{endif}}
{{if !$blog->latestEntry()->num_comments}}
<li class='ipsType_light'>{lang="num_comments" pluralize="$blog->latestEntry()->num_comments"}</li>
{{else}}
<li><a href='{$blog->latestEntry()->url()}#comments' title='{lang="see_comments_on_entry"}'>{lang="num_comments" pluralize="$blog->latestEntry()->num_comments"}</a></li>
{{endif}}
</ul>
{{else}}
<p class='ipsEmpty ipsType_center'>{lang="no_entries_yet"}</p>
{{endif}}
</div>
</div>
</li>
{{endforeach}}
</ol>
{{endif}}]]></template>
<template template_group="widgets" template_name="blogStatistics" template_data="$stats, $orientation='vertical'" template_location="front" template_app="blog"><![CDATA[<h3 class='ipsType_reset ipsWidget_title'>{lang="block_blogStatistics"}</h3>
<div class='ipsWidget_inner'>
{{if $orientation == 'vertical'}}
@@ -1186,8 +1324,8 @@
{template="userPhoto" app="core" params="$entry->author(), 'tiny'" group="global"}
</div>
<div class='ipsDataItem_main'>
<a href="{$entry->url()}" title='{lang="view_this_entry" sprintf="$entry->_title"}' class='ipsType_normal ipsType_break'>{wordbreak="$entry->name"}</a><br>
<span class='ipsType_light ipsType_medium ipsType_break ipsContained'>{lang="byline_nodate" htmlsprintf="$entry->author()->link()"} {lang="in"} <a href='{$entry->container()->url()}' class='ipsType_blendLinks'>{$entry->container()->_title}</a></span>
<a href="{$entry->url('getLastComment')}" title='{lang="view_this_entry" sprintf="$entry->_title"}' class='ipsType_medium ipsType_break'>{wordbreak="$entry->name"}</a><br>
<span class='ipsType_blendLinks ipsType_light ipsType_medium ipsType_break ipsContained'>{lang="byline_nodate" htmlsprintf="$entry->author()->link()"} {lang="in"} <a href='{$entry->container()->url()}' class='ipsType_blendLinks'>{$entry->container()->_title}</a></span>
{{if \IPS\Settings::i()->blog_enable_rating}}
{template="rating" group="global" location="front" app="core" params="'small', $entry->averageRating()"} &nbsp;&nbsp;
{{endif}}
+14 -1
View File
@@ -84,5 +84,18 @@
"100042": "4.0.12",
"100043": "4.0.12.1",
"100044": "4.0.13",
"100045": "4.0.13.1"
"100045": "4.0.13.1",
"101000": "4.1.0 Beta 1",
"101001": "4.1.0 Beta 2",
"101002": "4.1.0 Beta 3",
"101003": "4.1.0 Beta 4",
"101004": "4.1.0 Beta 5",
"101005": "4.1.0 Beta 6",
"101006": "4.1.0 Beta 7",
"101007": "4.1.0 Beta 8",
"101008": "4.1.0 Beta 9",
"101009": "4.1.0 Beta 10",
"101010": "4.1.0",
"101011": "4.1.1",
"101012": "4.1.2"
}
+22
View File
@@ -17,5 +17,27 @@
"allow_reuse": true,
"menu_style": "modal",
"embeddable": true
},
"blogCommentFeed": {
"class": "\\IPS\\Widget\\PermissionCache",
"restrict": [
"sidebar",
"cms"
],
"default_area": "",
"allow_reuse": true,
"menu_style": "modal",
"embeddable": true
},
"blogs": {
"class": "\\IPS\\Widget\\PermissionCache",
"restrict": [
"sidebar",
"cms"
],
"default_area": "",
"allow_reuse": true,
"menu_style": "menu",
"embeddable": true
}
}
@@ -23,14 +23,28 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
* @brief Content Router extension: Entries
*/
class _Blog
{
/**
* @brief Content Item Classes
*/
public $classes = array( 'IPS\blog\Entry' );
{
/**
* @brief Owned Node Classes
*/
public $ownedNodes = array( 'IPS\blog\Blog' );
/**
* @brief Content Item Classes
*/
public $classes = array();
/**
* Constructor
*
* @param \IPS\Member|NULL $member If checking access, the member to check for, or NULL to not check access
* @return void
*/
public function __construct( \IPS\Member $member = NULL )
{
if ( $member === NULL or $member->canAccessModule( \IPS\Application\Module::get( 'blog', 'blogs', 'front' ) ) )
{
$this->classes[] = 'IPS\blog\Entry';
}
}
}
@@ -22,8 +22,18 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* Front Navigation Extension: Blogs
*/
class _Blogs
class _Blogs extends \IPS\core\FrontNavigation\FrontNavigationAbstract
{
/**
* Get Type Title which will display in the AdminCP Menu Manager
*
* @return string
*/
public static function typeTitle()
{
return \IPS\Member::loggedIn()->language()->addToStack('frontnavigation_blogs');
}
/**
* Can access?
*
@@ -31,7 +41,7 @@ class _Blogs
*/
public function canView()
{
return !\IPS\Application::load('blog')->hide_tab and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'blog', 'blogs' ) );
return parent::canView() and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'blog', 'blogs' ) );
}
/**
@@ -63,14 +73,4 @@ class _Blogs
{
return \IPS\Dispatcher::i()->application->directory === 'blog';
}
/**
* Children
*
* @return array
*/
public function children()
{
return array();
}
}
@@ -27,7 +27,7 @@ class _Blog
/**
* Process Form
*
* @param \IPS\Form\Tabbed $form The form
* @param \IPS\Helpers\Form $form The form
* @param \IPS\Member\Group $group Existing Group
* @return void
*/
@@ -40,8 +40,9 @@ class _Blog
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowprivate', $group->g_blog_allowprivate, FALSE, array(), NULL, NULL, NULL, 'g_blog_allowprivate'));
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowownmod', $group->g_blog_allowownmod, FALSE, array(), NULL, NULL, NULL, 'g_blog_allowownmod'));
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowdelete', $group->g_blog_allowdelete, FALSE, array(), NULL, NULL, NULL, 'g_blog_allowdelete'));
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowcomment', $group->g_blog_allowcomment));
}
$form->add(new \IPS\Helpers\Form\YesNo('g_blog_allowcomment', $group->g_blog_allowcomment));
}
/**
@@ -60,7 +61,8 @@ class _Blog
$group->g_blog_allowprivate = $values['g_blog_allowprivate'];
$group->g_blog_allowownmod = $values['g_blog_allowownmod'];
$group->g_blog_allowdelete = $values['g_blog_allowdelete'];
$group->g_blog_allowcomment = $values['g_blog_allowcomment'];
}
$group->g_blog_allowcomment = $values['g_blog_allowcomment'];
}
}
@@ -49,7 +49,7 @@ class _Upgrade
$file = \IPS\File::create( 'core_Attachment', $entry['entry_image'], NULL, NULL, FALSE, $filePath );
$attachment = $file->makeAttachment('');
$fileName = htmlentities( $attachment['attach_file'], \IPS\HTMLENTITIES, 'UTF-8', TRUE );
$fileName = htmlspecialchars( $attachment['attach_file'], \IPS\HTMLENTITIES, 'UTF-8', TRUE );
$image = <<<IMAGE
<a href="<fileStore.core_Attachment>/{$file}" class="ipsAttachLink ipsAttachLink_image" style="float:left;"><img data-fileid="{$attachment['attach_id']}" src="<fileStore.core_Attachment>/{$file}" class="ipsImage ipsImage_thumbnailed" style="margin:10px;" alt="{$fileName}"></a>
@@ -0,0 +1,26 @@
{
"1": {
"method": "dropColumn",
"params": [
"blog_blogs",
"blog_view_level"
]
},
"2": {
"method": "changeIndex",
"params": [
"blog_blogs",
"blog_grabber",
{
"type": "key",
"name": "blog_grabber",
"length": [
null
],
"columns": [
"blog_disabled"
]
}
]
}
}
@@ -78,9 +78,9 @@ class _Upgrade
}
/* Set language strings */
\IPS\Lang::saveCustom( 'blog', "blogs_blog_{$blog->id}", html_entity_decode( $original['blog_name'], ENT_QUOTES, 'UTF-8' ) );
\IPS\Lang::saveCustom( 'blog', "blogs_blog_{$blog->id}", \IPS\Text\Parser::utf8mb4SafeDecode( $original['blog_name'] ) );
\IPS\Lang::saveCustom( 'blog', "blogs_blog_{$blog->id}_desc", \IPS\Text\Parser::parseStatic( $original['blog_desc'], TRUE, NULL, NULL, TRUE, TRUE, TRUE ) );
\IPS\Lang::saveCustom( 'blog', "blogs_groupblog_name_{$blog->id}", html_entity_decode( $original['blog_groupblog_name'], ENT_QUOTES, 'UTF-8' ) );
\IPS\Lang::saveCustom( 'blog', "blogs_groupblog_name_{$blog->id}", \IPS\Text\Parser::utf8mb4SafeDecode( $original['blog_groupblog_name'] ) );
$blog->save();
}
+14 -14
View File
@@ -81,7 +81,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
/**
* @brief Icon
*/
public static $icon = 'file-text-o';
public static $icon = 'file-text';
/**
* @brief [Node] If the node can be "owned", the owner "type" (typically "member" or "group") and the associated database column
@@ -473,19 +473,19 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
}
/**
* Get URL
*
* @return \IPS\Http\Url
* @brief URL Base
*/
public function url()
{
if( $this->_url === NULL )
{
$this->_url = \IPS\Http\Url::internal( "app=blog&module=blogs&controller=view&id={$this->_id}", 'front', 'blogs_blog', array( $this->seo_name ) );
}
return $this->_url;
}
public static $urlBase = 'app=blog&module=blogs&controller=view&id=';
/**
* @brief URL Base
*/
public static $urlTemplate = 'blogs_blog';
/**
* @brief SEO Title Column
*/
public static $seoTitleColumn = 'seo_name';
/**
* @brief Cached latest entry
@@ -672,7 +672,7 @@ class _Blog extends \IPS\Node\Model implements \IPS\Node\Ratings, \IPS\Content\E
*/
protected function get__title()
{
return htmlentities( \IPS\Member::loggedIn()->language()->get( static::$titleLangPrefix . $this->_id ), ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE );
return htmlspecialchars( \IPS\Member::loggedIn()->language()->get( static::$titleLangPrefix . $this->_id ), ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE );
}
/**
+1 -1
View File
@@ -70,7 +70,7 @@ class _Feed extends \IPS\Patterns\ActiveRecord
if ( $article['link'] )
{
$link = htmlentities( $this->import_show_link, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE );
$link = htmlspecialchars( $this->import_show_link, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE );
$entry->content .= "<br><p><a href='{$article['link']}'>{$link}</a></p>";
}
+1 -1
View File
@@ -73,7 +73,7 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
/**
* @brief Icon
*/
public static $icon = 'file-text-o';
public static $icon = 'file-text';
/**
* @brief Reputation Type
+18 -26
View File
@@ -120,7 +120,7 @@ class _Entry extends \IPS\Content\Item implements
/**
* @brief Icon
*/
public static $icon = 'file-text-o';
public static $icon = 'file-text';
/**
* @brief The map of permission columns
@@ -203,29 +203,21 @@ class _Entry extends \IPS\Content\Item implements
* @brief Cached URLs
*/
protected $_url = array();
/**
* Get URL
*
* @param string|NULL $action Action
* @return \IPS\Http\Url
*/
public function url( $action=NULL )
{
$_key = md5( $action );
if( !isset( $this->_url[ $_key ] ) )
{
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=blog&module=blogs&controller=entry&id={$this->id}", 'front', 'blog_entry', $this->name_seo );
if ( $action )
{
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( 'do', $action );
}
}
return $this->_url[ $_key ];
}
/**
* @brief URL Base
*/
public static $urlBase = 'app=blog&module=blogs&controller=entry&id=';
/**
* @brief URL Base
*/
public static $urlTemplate = 'blog_entry';
/**
* @brief SEO Title Column
*/
public static $seoTitleColumn = 'name_seo';
/**
* Can view this entry
@@ -307,13 +299,13 @@ class _Entry extends \IPS\Content\Item implements
}
/**
* Additional WHERE clauses for New Content view
* Additional WHERE clauses for Follow view
*
* @param bool $joinContainer If true, will join container data (set to TRUE if your $where clause depends on this data)
* @param array $joins Other joins
* @return array
*/
public static function vncWhere( &$joinContainer, &$joins )
public static function followWhere( &$joinContainer, &$joins )
{
$joinContainer = TRUE;
if ( \IPS\Member::loggedIn()->member_id )
@@ -325,7 +317,7 @@ class _Entry extends \IPS\Content\Item implements
$where = array( \IPS\Content::socialGroupGetItemsWithPermissionWhere( 'blog_blogs.blog_social_group', \IPS\Member::loggedIn() ) );
}
return array_merge( parent::vncWhere( $joinContainer, $joins ), $where );
return array_merge( parent::followWhere( $joinContainer, $joins ), $where );
}
/**
@@ -0,0 +1,58 @@
<?php
/**
* @brief blogCommentFeed Widget
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage blog
* @since 13 Jul 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\blog\widgets;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* blogCommentFeed Widget
*/
class _blogCommentFeed extends \IPS\Content\WidgetComment
{
/**
* @brief Widget Key
*/
public $key = 'blogCommentFeed';
/**
* @brief App
*/
public $app = 'blog';
/**
* @brief Plugin
*/
public $plugin = '';
/**
* Class
*/
protected static $class = 'IPS\blog\Entry\Comment';
/**
* Get where clause
*
* @return array
*/
protected function buildWhere()
{
$where = parent::buildWhere();
$where['item'][] = array( 'entry_status!=?', 'draft' );
return $where;
}
}
+146
View File
@@ -0,0 +1,146 @@
<?php
/**
* @brief blogs Widget
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage blog
* @since 13 Jul 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\blog\widgets;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* blogs Widget
*/
class _blogs extends \IPS\Widget\PermissionCache
{
/**
* @brief Widget Key
*/
public $key = 'blogs';
/**
* @brief App
*/
public $app = 'blog';
/**
* @brief Plugin
*/
public $plugin = '';
/**
* Specify widget configuration
*
* @param null|\IPS\Helpers\Form $form Form object
* @return null|\IPS\Helpers\Form
*/
public function configuration( &$form=null )
{
if ( $form === null )
{
$form = new \IPS\Helpers\Form;
}
/* Block title */
$form->add( new \IPS\Helpers\Form\Text( 'widget_feed_title', isset( $this->configuration['widget_feed_title'] ) ? $this->configuration['widget_feed_title'] : \IPS\Member::loggedIn()->language()->addToStack( 'blogs' ) ) );
/* Author */
$author = NULL;
try
{
if ( isset( $this->configuration['widget_feed_author'] ) and is_array( $this->configuration['widget_feed_author'] ) )
{
foreach( $this->configuration['widget_feed_author'] as $id )
{
$author[ $id ] = \IPS\Member::load( $id );
}
}
}
catch( \OutOfRangeException $ex ) { }
$form->add( new \IPS\Helpers\Form\Member( 'widget_feed_author', $author, FALSE, array( 'multiple' => true ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'widget_blog_last_date', isset( $this->configuration['widget_blog_last_date'] ) ? $this->configuration['widget_blog_last_date'] : '0', FALSE, array(
'options' => array(
0 => 'show_all',
1 => 'today',
5 => 'last_5_days',
7 => 'last_7_days',
10 => 'last_10_days',
15 => 'last_15_days',
20 => 'last_20_days',
25 => 'last_25_days',
30 => 'last_30_days',
60 => 'last_60_days',
90 => 'last_90_days',
)
) ) );
/* Number to show */
$form->add( new \IPS\Helpers\Form\Number( 'widget_feed_show', isset( $this->configuration['widget_feed_show'] ) ? $this->configuration['widget_feed_show'] : 5, TRUE ) );
$form->add( new \IPS\Helpers\Form\Select( 'widget_feed_sort_on', isset( $this->configuration['widget_feed_sort_on'] ) ? $this->configuration['widget_feed_sort_on'] : 'blog_edate', FALSE, array( 'options' => array(
'blog_edate' => 'widget__blog_edate',
'blog_entries' => 'widget__blog_count_entries',
'blog_comments' => 'widget__blog_count_comments'
) ) ), NULL, NULL, NULL, 'widget_feed_sort_on' );
$form->add( new \IPS\Helpers\Form\Select( 'widget_feed_sort_dir', isset( $this->configuration['widget_feed_sort_dir'] ) ? $this->configuration['widget_feed_sort_dir'] : 'desc', FALSE, array(
'options' => array(
'desc' => 'descending',
'asc' => 'ascending'
)
) ) );
}
/**
* Render a widget
*
* @return string
*/
public function render()
{
$where = array( array( 'blog_disabled=0 AND blog_social_group IS NULL' ) );
$sortBy = ( isset( $this->configuration['widget_feed_sort_on'] ) and isset( $this->configuration['widget_feed_sort_dir'] ) ) ? ( $this->configuration['widget_feed_sort_on'] . ' ' . $this->configuration['widget_feed_sort_dir'] ) : NULL;
$limit = isset( $this->configuration['widget_feed_show'] ) ? $this->configuration['widget_feed_show'] : 5;
if ( isset( $this->configuration['widget_feed_author'] ) and is_array( $this->configuration['widget_feed_author'] ) )
{
$where[] = array( \IPS\Db::i()->in( 'blog_member_id', $this->configuration['widget_feed_author'] ) );
}
/* Get results */
$blogs = array();
foreach( \IPS\Db::i()->select( '*', 'blog_blogs', $where, $sortBy, array( 0, $limit ) ) as $row )
{
$blog = \IPS\blog\Blog::constructFromData( $row );
$blog->coverPhoto()->editable = false;
$blogs[] = $blog;
}
if ( count( $blogs ) )
{
return $this->output( $blogs, isset( $this->configuration['widget_feed_title'] ) ? $this->configuration['widget_feed_title'] : \IPS\Member::loggedIn()->language()->addToStack( 'blogs' ) );
}
else
{
return '';
}
}
}
+12 -12
View File
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<emails><template><template_app>calendar</template_app><template_name>digests__item</template_name><template_content_html><![CDATA[<tr style='border-bottom: 1px solid #eeeeee'>
<td width='120' valign='top' align='center'>
<td dir='{dir}' width='120' valign='top' align='center'>
<table width='120' cellpadding='10' cellspacing='0' border='0' bgcolor='#fafafa'>
<tr>
<td>
<td dir='{dir}'>
<table width='100' cellpadding='0' cellspacing='0' border='0' bgcolor='#ffffff' style='border: 1px solid #cccccc;'>
<tr>
<td align='center' style="color: #a93848; font-size: 18px; line-height: 30px; text-transform: uppercase; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: bold; padding-top: 5px;">
<td dir='{dir}' align='center' style="color: #a93848; font-size: 18px; line-height: 30px; text-transform: uppercase; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: bold; padding-top: 5px;">
{$event->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->monthNameShort}
</td>
</tr>
<tr>
<td align='center' style="color: #333333; line-height: 40px; font-size: 44px; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: 300; padding-bottom: 10px">
<td dir='{dir}' align='center' style="color: #333333; line-height: 40px; font-size: 44px; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: 300; padding-bottom: 10px">
{$event->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->mday}
</td>
</tr>
@@ -20,7 +20,7 @@
</tr>
</table>
</td>
<td align='left'>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
{$email->language->addToStack("x_created_event_in", FALSE, array( 'sprintf' => array( $event->author()->name, $event->container()->_title ) ) )}
</p>
@@ -44,7 +44,7 @@
{{if $event->rsvp}}
<div style="font-size: 13px; font-family: 'Helvetica Neue', helvetica, sans-serif; margin-top: 10px">
{{if $attendees = $row->attendees()}}{{endif}}
{{if $attendees = $event->attendees()}}{{endif}}
<strong style="text-transform: uppercase; font-size: 12px; font-family: 'Helvetica Neue', helvetica, sans-serif;">{$email->language->addToStack("digest_users_going", FALSE, array( 'pluralize' => array( count( $attendees[1] ) ) ) )}</strong>
{{if count( $attendees[1] )}}
{{foreach $attendees[1] as $idx => $attendee}}
@@ -74,18 +74,18 @@
</td>
</tr>]]></template_content_html><template_data>$event, $email</template_data><template_content_plaintext><![CDATA[{$email->language->addToStack("x_created_event_in", FALSE, array( 'sprintf' => array( $event->author()->name, $event->container()->_title ) ) )}: {$event->title} ({$event->url()})
]]></template_content_plaintext></template><template><template_app>calendar</template_app><template_name>digests__comment</template_name><template_content_html><![CDATA[<tr style='border-bottom: 1px solid #eeeeee'>
<td width='120' valign='top' align='center'>
<td dir='{dir}' width='120' valign='top' align='center'>
<table width='120' cellpadding='10' cellspacing='0' border='0' bgcolor='#fafafa'>
<tr>
<td>
<td dir='{dir}'>
<table width='100' cellpadding='0' cellspacing='0' border='0' bgcolor='#ffffff' style='border: 1px solid #cccccc;'>
<tr>
<td align='center' style="color: #a93848; font-size: 18px; line-height: 30px; text-transform: uppercase; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: bold; padding-top: 5px;">
<td dir='{dir}' align='center' style="color: #a93848; font-size: 18px; line-height: 30px; text-transform: uppercase; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: bold; padding-top: 5px;">
{$comment->item()->nextOccurrence( $today, 'startDate' )->monthNameShort}
</td>
</tr>
<tr>
<td align='center' style="color: #333333; line-height: 40px; font-size: 44px; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: 300; padding-bottom: 10px">
<td dir='{dir}' align='center' style="color: #333333; line-height: 40px; font-size: 44px; font-family: 'Helvetica Neue', helvetica, sans-serif; font-weight: 300; padding-bottom: 10px">
{$comment->item()->nextOccurrence( $today, 'startDate' )->mday}
</td>
</tr>
@@ -94,7 +94,7 @@
</tr>
</table>
</td>
<td align='left'>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
{$email->language->addToStack("x_commented_event", FALSE, array( 'sprintf' => array( $comment->author()->name ) ) )}
</p>
@@ -102,7 +102,7 @@
<a href='{$comment->item()->url()}' style='text-decoration: none;'>{$comment->item()->name}</a>
</h2>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; color: #8c8c8c; font-size: 13px;'>
{$email->language->addToStack("email_event_on", FALSE)} {$comment->item()->_start_date->dayName} {$comment->item()->_start_date->mday} {$comment->item()->_start_date->monthName} {$comment->item()->_start_date->year}{{if !$comment->item()->all_day}}, {$comment->item()->_start_date->localeTime( FALSE )}{{endif}}
{$email->language->addToStack("digest_event_on", FALSE)} {$comment->item()->_start_date->dayName} {$comment->item()->_start_date->mday} {$comment->item()->_start_date->monthName} {$comment->item()->_start_date->year}{{if !$comment->item()->all_day}}, {$comment->item()->_start_date->localeTime( FALSE )}{{endif}}
{{if $comment->item()->_end_date}}
&nbsp;&nbsp;&raquo;&nbsp;&nbsp;
{$comment->item()->_end_date->dayName} {$comment->item()->_end_date->mday} {$comment->item()->_end_date->monthName} {$comment->item()->_end_date->year}{{if !$comment->item()->all_day}}, {$comment->item()->_end_date->localeTime( FALSE )}{{endif}}
+14 -8
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<javascript app="calendar">
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.main.js" javascript_type="controller" javascript_version="100045" javascript_position="1000050"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.main.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -109,7 +109,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.monthView.js" javascript_type="controller" javascript_version="100045" javascript_position="1000050"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.monthView.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -251,7 +251,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/submit" javascript_name="ips.submit.dates.js" javascript_type="controller" javascript_version="100045" javascript_position="1000100"><![CDATA[/**
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/submit" javascript_name="ips.submit.dates.js" javascript_type="controller" javascript_version="101012" javascript_position="1000100"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -451,10 +451,17 @@
*/
_getDate: function(input) {
/* jQuery UI Polyfill needs to be changed into the correct format */
if ( input.hasClass('hasDatepicker') ) {
if( !ips.utils.time.supportsHTMLDate() ) {
/* If it has been initiated, we can use the getDate method */
try {
return input.datepicker( "getDate" );
var thisDate = input.datepicker( "getDate" );
if( _.isNull( thisDate ) )
{
thisDate = new Date( input.attr('value') );
}
return thisDate;
}
/* If it hasn't we can pull the 'value' attribute which can't have been changed yet. Not .val() as that will be in the wrong format */
catch(err) {
@@ -484,7 +491,7 @@
}
// We need to add the offset to ensure the day stays correct
if ( this.scope.find( 'input[name="event_dates[start_date]"]' ).hasClass('hasDatepicker') ) {
if( !ips.utils.time.supportsHTMLDate() ){
startDate.setTime( startDate.getTime() - new Date().getTimezoneOffset()*60000 );
}
@@ -497,8 +504,7 @@
// If we have a valid end date...
if( !singleDay.is(':checked') && ips.utils.time.isValidDateObj( endDate ) ){
if ( this.scope.find('input[name="event_dates[end_date]"]' ).hasClass( 'hasDatepicker' ) )
{
if( !ips.utils.time.supportsHTMLDate() ){
endDate.setTime( endDate.getTime() - new Date().getTimezoneOffset()*60000 );
}
endDateString = ips.utils.time.localeDateString( endDate, { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' } );
+4 -1
View File
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<language>
<app key="calendar" version="100045">
<app key="calendar" version="101012">
<word key="__app_calendar" js="0">Calendar</word>
<word key="frontnavigation_calendar" js="0">Calendar</word>
<word key="__indefart_calendar_event_comment" js="0">a comment on a calendar event</word>
<word key="__indefart_calendar_event" js="0">a calendar event</word>
<word key="__indefart_calendar_event_review" js="0">a review on a calendar event</word>
<word key="calendar_event_container" js="0">calendar</word>
<word key="menu__calendar_calendars" js="0">Calendar</word>
<word key="menu__calendar_calendars_calendars" js="0">Calendars</word>
<word key="menu__calendar_calendars_ical" js="0">iCalendar Feeds</word>
@@ -322,6 +323,7 @@
<word key="no_recent_reviews" js="0">No recent reviews found</word>
<word key="announce_calendars" js="0">Calendars</word>
<word key="review_count" js="0">Number of reviews to show</word>
<word key="widget_calendar" js="0">Calendar</word>
<word key="embed_calendar_event" js="0">Calendar Event</word>
<word key="x_users_going" js="0">{# [1:user][?:users]} going</word>
<word key="timezone_offset_short" js="0">GMT %s</word>
@@ -366,6 +368,7 @@
<word key="timezone_offset_14" js="0">[GMT + 14] Line Island Time</word>
<word key="task__icalendar" js="0">Checks iCalendar feeds for new events and imports into IP.Calendar.</word>
<word key="digest_area_calendar" js="0">Events</word>
<word key="digest_area_event" js="0">Event</word>
<word key="x_created_event_in" js="0">%s posted an event in %s</word>
<word key="x_commented_event" js="0">%s commented on an event</word>
<word key="digest_event_on" js="0">Event on</word>
+1 -1
View File
@@ -21,7 +21,7 @@
},
{
"key": "ipb_calendar_mon",
"default": "1"
"default": "0"
},
{
"key": "show_bday_calendar",
+182 -71
View File
@@ -133,8 +133,8 @@
</div>
{{endif}}
<span class="ipsType_pageTitle">
<a href='#elCalendars_menu' id='elCalendars' data-ipsMenu data-ipsMenu-appendTo="#elCalendarsHeader">{{if $thisCalendar}}{$thisCalendar->_title}{{else}}{lang="all_calendars"}{{endif}} &nbsp;<i class='fa fa-caret-down'></i></a>
&nbsp;&nbsp;<a href='#elCalendarSettings_menu' id='elCalendarSettings' data-ipsMenu data-ipsMenu-alignCenter data-ipsMenu-appendTo="#elCalendarsHeader"><i class='fa fa-cog'></i></a>
<a href='#elCalendars_menu' id='elCalendars' data-ipsMenu data-ipsMenu-appendTo="#elCalendarsHeader" class='ipsType_blendLinks'>{{if $thisCalendar}}{$thisCalendar->_title}{{else}}{lang="all_calendars"}{{endif}} &nbsp;<i class='fa fa-caret-down'></i></a>
&nbsp;&nbsp;<a href='#elCalendarSettings_menu' id='elCalendarSettings' data-ipsMenu data-ipsMenu-alignCenter data-ipsMenu-appendTo="#elCalendarsHeader" class='ipsType_blendLinks'><i class='fa fa-cog'></i></a>
{{if ( $thisCalendar AND $thisCalendar->can('add') ) OR ( !$thisCalendar AND \IPS\calendar\Calendar::canOnAny('add') )}}
&nbsp;&nbsp;
{{if $thisCalendar}}
@@ -417,7 +417,7 @@
{{foreach $collection as $input}}
{{if $input instanceof \IPS\Helpers\Form\Date}}
<li class='ipsFieldRow ipsFieldRow_fullWidth'>
<input type="date" data-control="date" placeholder="{lang="jump_to_placeholder"}" name='{$input->name}' id='{$input->htmlId}' {{if $input->required === TRUE}}required aria-required='true'{{endif}} value="{{if $input->defaultValue instanceof \IPS\DateTime}}{$input->defaultValue->format('Y-m-d')}{{endif}}">
<input type="date" data-control="date" placeholder="{lang="jump_to_placeholder"}" name='{$input->name}' id='{$input->htmlId}' {{if $input->required === TRUE}}required{{endif}} value="{{if $input->defaultValue instanceof \IPS\DateTime}}{$input->defaultValue->format('Y-m-d')}{{endif}}">
</li>
{{else}}
{$input->rowHtml($form)|raw}
@@ -501,6 +501,97 @@
</ul>
</div>
</div>]]></template>
<template template_group="global" template_name="manageFollowRow" template_data="$table, $headers, $rows, $includeFirstCommentInCommentCount=TRUE" template_location="front" template_app="calendar"><![CDATA[{{if count( $rows )}}
{{foreach $rows as $row}}
{{$idField = $row::$databaseColumnId;}}
<li class="ipsDataItem ipsDataItem_responsivePhoto {{if $row->unread()}}ipsDataItem_unread{{endif}} {{if method_exists( $row, 'tableClass' ) && $row->tableClass()}}ipsDataItem_{$row->tableClass()}{{endif}} {{if $row->hidden()}}ipsModerated{{endif}}" data-controller='core.front.system.manageFollowed' data-followID='{$row->_followData['follow_area']}-{$row->_followData['follow_rel_id']}'>
<div class='ipsDataItem_generic ipsDataItem_size2'>
{{if $row->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )}}
<time datetime='{$row->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_large'>
<span class='ipsCalendarDate_month'>{$row->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$row->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' )->mday}</span>
</time>
{{else}}
<time datetime='{$row->lastOccurrence( 'startDate' )->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_large'>
<span class='ipsCalendarDate_month'>{$row->lastOccurrence( 'startDate' )->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$row->lastOccurrence( 'startDate' )->mday}</span>
</time>
{{endif}}
</div>
<div class='ipsDataItem_main ipsPos_middle'>
<h4 class='ipsDataItem_title ipsType_break ipsType_normal'>
{{if $row->mapped('locked')}}
<i class="fa fa-lock"></i>
{{endif}}
{{if $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}}
<span>
{{if $row->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $row->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $row->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $row->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
</span>
{{endif}}
{{if $row->prefix()}}
{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}
{{endif}}
<a href='{$row->url()}'>
{{if $row->mapped('title')}}{wordbreak="$row->mapped('title')"}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</a>
</h4>
<div class='ipsDataItem_meta ipsType_light ipsType_blendLinks' data-ipsTruncate data-ipsTruncate-size='2 lines' data-ipsTruncate-type='remove'>
{{if method_exists( $row, 'tableDescription' )}}
{$row->tableDescription()|raw}
{{else}}
{lang="byline" htmlsprintf="$row->author()->link( $row->warningRef() )"}{datetime="$row->__get( $row::$databaseColumnMap['date'] )"}
{lang="in"} <a href="{$row->container()->url()}">{$row->container()->_title}</a>
{{endif}}
</div>
</div>
<div class='ipsDataItem_generic ipsDataItem_size1 ipsType_center ipsType_large'>
<span class='ipsBadge ipsBadge_icon ipsBadge_new {{if !$row->_followData['follow_is_anon']}}ipsHide{{endif}}' data-role='followAnonymous' data-ipsTooltip title='{lang="follow_is_anon"}'><i class='fa fa-eye-slash'></i></span>
</div>
<div class='ipsDataItem_generic ipsDataItem_size6'>
<ul class='ipsList_reset'>
<li title='{lang="follow_when"}' data-role='followDate'><i class='fa fa-clock-o'></i> {datetime="$row->_followData['follow_added']"}</li>
<li title='{lang="follow_how"}' data-role='followFrequency'>
{{if $row->_followData['follow_notify_freq'] == 'none'}}
<i class='fa fa-bell-slash-o'></i>
{{else}}
<i class='fa fa-bell'></i>
{{endif}} {lang="follow_freq_{$row->_followData['follow_notify_freq']}"}
</li>
</ul>
</div>
<div class='ipsDataItem_generic ipsDataItem_size6 ipsType_center'>
{template="manageFollow" group="system" app="core" params="$row->_followData['follow_app'], $row->_followData['follow_area'], $row->_followData['follow_rel_id']"}
</div>
{{if $table->canModerate()}}
<div class='ipsDataItem_modCheck'>
<span class='ipsCustomInput'>
<input type='checkbox' data-role='moderation' name="moderate[{$row->$idField}]" data-actions="{expression="implode( ' ', $table->multimodActions( $row ) )"}" data-state='{{if $row->tableStates()}}{$row->tableStates()}{{endif}}'>
<span></span>
</span>
</div>
{{endif}}
</li>
{{endforeach}}
{{endif}}
]]></template>
<template template_group="global" template_name="rows" template_data="$table, $headers, $rows" template_location="front" template_app="calendar"><![CDATA[{{if count( $rows )}}
{{foreach $rows as $row}}
<li class="ipsDataItem {{if method_exists( $row, 'tableClass' ) && $row->tableClass()}}ipsDataItem_{$row->tableClass()}{{endif}} {{if $row->hidden()}}ipsModerated{{endif}}">
@@ -523,14 +614,6 @@
<i class="fa fa-lock"></i>
{{endif}}
{{if $row->prefix()}}
{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}
{{endif}}
<a href='{$row->url()}' class='ipsType_break' {{if $row->tableHoverUrl}}data-ipsHover{{endif}}>
{{if $row->mapped('title')}}{wordbreak="$row->mapped('title')"}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</a>
{{if $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}}
{{if $row->hidden() === -1}}
<span class="ipsBadge ipsBadge_small ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
@@ -544,6 +627,14 @@
<span class="ipsBadge ipsBadge_small ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
{{if $row->prefix()}}
{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}
{{endif}}
<a href='{$row->url()}' class='ipsType_break' {{if $row->tableHoverUrl}}data-ipsHover{{endif}}>
{{if $row->mapped('title')}}{wordbreak="$row->mapped('title')"}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</a>
</h4>
<div class='ipsDataItem_meta ipsType_light ipsType_blendLinks'>
{$row->eventBlurb()|raw}
@@ -613,76 +704,89 @@
{{if $table->canModerate()}}
<div class='ipsDataItem_modCheck'>
{{$idField = $row::$databaseColumnId;}}
<input type='checkbox' data-role='moderation' name="moderate[{$row->$idField}]" data-actions="{expression="implode( ' ', $table->multimodActions( $row ) )"}" data-state='{{if $row->tableStates()}}{$row->tableStates()}{{endif}}'>
<span class='ipsCustomInput'>
<input type='checkbox' data-role='moderation' name="moderate[{$row->$idField}]" data-actions="{expression="implode( ' ', $table->multimodActions( $row ) )"}" data-state='{{if $row->tableStates()}}{$row->tableStates()}{{endif}}'>
<span></span>
</span>
</div>
{{endif}}
</li>
{{endforeach}}
{{endif}}]]></template>
<template template_group="global" template_name="snippet" template_data="$activity, $type='activity'" template_location="front" template_app="calendar"><![CDATA[
{{if $activity instanceof \IPS\calendar\Event\Comment or $activity instanceof \IPS\calendar\Event\Review}}
{{$item = $activity->item();}}
<template template_group="global" template_name="searchResultCommentSnippet" template_data="$indexData, $nextOccurance, $startDate, $endDate, $allDay, $reviewRating, $condensed" template_location="front" template_app="calendar"><![CDATA[{{if $condensed}}
<time datetime='{$nextOccurance->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_small ipsPos_left'>
<span class='ipsCalendarDate_month'>{$nextOccurance->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$nextOccurance->mday}</span>
</time>
{{else}}
{{$item = $activity;}}
{{endif}}
<div class='cSearchActivity_info ipsContained'>
<div class='ipsColumns'>
<div class='ipsColumn ipsColumn_veryNarrow'>
{{$date = ( $item->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' ) == NULL ) ? $item->lastOccurrence() : $item->nextOccurrence( \IPS\calendar\Date::getDate(), 'startDate' );}}
<time datetime='{$date->mysqlDatetime()}' class='ipsCalendarDate'>
<span class='ipsCalendarDate_month'>{$date->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$date->mday}</span>
<div class='ipsColumns ipsColumns_collapsePhone ipsColumns_noSpacing'>
<div class='ipsColumn ipsColumn_narrow'>
<time datetime='{$nextOccurance->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_large ipsPos_center'>
<span class='ipsCalendarDate_month'>{$nextOccurance->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$nextOccurance->mday}</span>
</time>
</div>
<div class='ipsColumn ipsColumn_fluid'>
{{if $activity instanceof \IPS\calendar\Event\Comment or $activity instanceof \IPS\calendar\Event\Review}}
{{if $activity instanceof \IPS\calendar\Event\Review}}
{template="rating" group="global" location="front" app="core" params="'large', $activity->mapped('rating'), \IPS\Settings::i()->reviews_rating_out_of"}
{{endif}}
<div class='ipsType_medium ipsType_richText ipsContained {{if $activity instanceof \IPS\calendar\Event\Review}}ipsSpacer_both{{else}}ipsSpacer_bottom{{endif}} ipsSpacer_half' data-ipsTruncate data-ipsTruncate-size='3 lines' data-ipsTruncate-type='remove'>
{$activity->truncated()|raw}
</div>
<ul class='ipsList_inline ipsType_light'>
{{if $activity instanceof \IPS\calendar\Event\Review}}
<li>{lang="x_members_found_helpful" sprintf="$activity->mapped('votes_helpful'), \IPS\Member::loggedIn()->language()->pluralize( \IPS\Member::loggedIn()->language()->get( 'x_members' ), array( $activity->mapped('votes_total') ) )"}</li>
{{endif}}
{{if $type != 'search' and $activity instanceof \IPS\Content\Reputation and settings.reputation_enabled}}
<li>{template="reputationMini" group="global" app="core" params="$activity, '', NULL, TRUE"}</li>
{{endif}}
</ul>
{{else}}
{{if $type != 'search'}}<a href='{$activity->url()}' class='ipsType_normal ipsType_break'>{$activity->mapped('title')}</a>{{endif}}
<p class='ipsType_reset ipsType_small'>
<strong>
<time itemprop='startDate' content='{expression="$item->_start_date->format( 'Y-m-d' )"}'>
{$item->_start_date->dayName} {$item->_start_date->mday} {$item->_start_date->monthName} {$item->_start_date->year}{{if !$item->all_day}}, {$item->_start_date->localeTime( FALSE )}{{endif}}
<div class='ipsStream_comment ipsPad'>
<p class='ipsType_reset ipsType_normal'>
<strong class='ipsType_normal'>
<time itemprop='startDate' content='{expression="$startDate->format( 'Y-m-d' )"}'>
{$startDate->dayName} {$startDate->mday} {$startDate->monthName} {$startDate->year}{{if !$allDay}}, {$startDate->localeTime( FALSE )}{{endif}}
</time>
{{if $item->_end_date}}
<em class='ipsType_light'>{lang="until"}</em>
<time itemprop='startDate' content='{expression="$item->_end_date->format( 'Y-m-d' )"}'>
{$item->_end_date->dayName} {$item->_end_date->mday} {$item->_end_date->monthName} {$item->_end_date->year}{{if !$item->all_day}}, {$item->_end_date->localeTime( FALSE )}{{endif}}
{{if $endDate}}
{lang="until_lc"}
<time itemprop='endDate' content='{expression="$endDate->format( 'Y-m-d' )"}'>
{$endDate->dayName} {$endDate->mday} {$endDate->monthName} {$endDate->year}{{if !$allDay}}, {$endDate->localeTime( FALSE )}{{endif}}
</time>
{{endif}}
</strong>
</p>
<div class='ipsType_medium ipsType_richText ipsContained ipsSpacer_both ipsSpacer_half' data-ipsTruncate data-ipsTruncate-size='3 lines' data-ipsTruncate-type='remove'>
{$activity->truncated()|raw}
{{if $reviewRating !== NULL}}
{template="rating" app="core" params="'medium', $reviewRating" group="global"}
{{endif}}
{{if trim( $indexData['index_content'] ) !== ''}}
<div class='ipsType_richText ipsType_break ipsType_medium ipsSpacer_top ipsSpacer_half' {{if !( \IPS\Dispatcher::i()->application->directory == 'core' and \IPS\Dispatcher::i()->module and \IPS\Dispatcher::i()->module->key == 'search' )}}data-ipsTruncate data-ipsTruncate-type='remove' data-ipsTruncate-size='3 lines'{{else}}data-searchable data-findTerm{{endif}}>
{$indexData['index_content']|raw}
</div>
{{endif}}
</div>
</div>
</div>
{{endif}}]]></template>
<template template_group="global" template_name="searchResultEventSnippet" template_data="$indexData, $itemData, $nextOccurance, $startDate, $endDate, $allDay, $condensed" template_location="front" template_app="calendar"><![CDATA[{{if $condensed}}
<time datetime='{$nextOccurance->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_small ipsPos_left'>
<span class='ipsCalendarDate_month'>{$nextOccurance->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$nextOccurance->mday}</span>
</time>
{{else}}
<div class='ipsColumns ipsColumns_collapsePhone'>
<div class='ipsColumn ipsColumn_narrow'>
<time datetime='{$nextOccurance->mysqlDatetime()}' class='ipsCalendarDate ipsCalendarDate_large ipsPos_center'>
<span class='ipsCalendarDate_month'>{$nextOccurance->monthNameShort}</span>
<span class='ipsCalendarDate_date'>{$nextOccurance->mday}</span>
</time>
</div>
<div class='ipsColumn ipsColumn_fluid ipsStream_snippetInfo'>
<strong class='ipsType_normal'>
<time itemprop='startDate' content='{expression="$startDate->format( 'Y-m-d' )"}'>
{$startDate->dayName} {$startDate->mday} {$startDate->monthName} {$startDate->year}{{if !$allDay}}, {$startDate->localeTime( FALSE )}{{endif}}
</time>
{{if $endDate}}
{lang="until_lc"}
<time itemprop='endDate' content='{expression="$endDate->format( 'Y-m-d' )"}'>
{$endDate->dayName} {$endDate->mday} {$endDate->monthName} {$endDate->year}{{if !$allDay}}, {$endDate->localeTime( FALSE )}{{endif}}
</time>
{{endif}}
</strong>
{{if trim( $indexData['index_content'] ) !== ''}}
<div class='ipsSpacer_top ipsSpacer_half ipsType_richText ipsType_break ipsType_medium' {{if !( \IPS\Dispatcher::i()->application->directory == 'core' and \IPS\Dispatcher::i()->module and \IPS\Dispatcher::i()->module->key == 'search' )}}data-ipsTruncate data-ipsTruncate-type='remove' data-ipsTruncate-size='2 lines'{{else}}data-searchable data-findTerm{{endif}}>
{$indexData['index_content']|raw}
</div>
<ul class='ipsList_inline ipsType_light'>
{{if $item->container()->allow_comments}}
<li>{lang="num_comments" pluralize="$activity->comments"}</li>
{{endif}}
{{if $item->container()->allow_reviews}}
<li>{lang="num_reviews" pluralize="$activity->reviews"} {{if $activity->reviews > 0}}&nbsp;&nbsp;{template="rating" group="global" location="front" app="core" params="'tiny', $item->rating, \IPS\Settings::i()->reviews_rating_out_of"}{{endif}}</li>
{{endif}}
{{if $type != 'search' and $item instanceof \IPS\Content\Reputation and settings.reputation_enabled}}
<li>{template="reputationMini" group="global" app="core" params="$activity, '', NULL, TRUE"}</li>
{{endif}}
</ul>
{{endif}}
</div>
</div>
</div>]]></template>
{{endif}}]]></template>
<template template_group="livesearch" template_name="calendar" template_data="$calendar" template_location="admin" template_app="calendar"><![CDATA[<li class='ipsPad_half ipsClearfix' data-role='result'>
<a href='{url="app=calendar&module=calendars&controller=calendars&do=form&id="}{$calendar->id}' class='ipsPos_left'>{$calendar->_title}</a>
</li>
@@ -878,7 +982,7 @@
<li>
<input type='radio' name='event_dates[repeat_end]' id='event_repeat_end_ondate' value='date'{{if $value['repeat_end_date']}} checked{{endif}}>
<div class='ipsField_fieldList_content'>
<label for="event_repeat_end_ondate">{lang="event_rpm_ends_date"}</label> <input type='date' name='event_dates[repeat_end_date]' class='cCalendar_shortInput' size='10' value='{$value['repeat_end_date']}'>
<label for="event_repeat_end_ondate">{lang="event_rpm_ends_date"}</label> <input type='date' name='event_dates[repeat_end_date]' class='cCalendar_shortInput' size='10' value='{{if $value['repeat_end_date'] instanceof \IPS\calendar\Date}}{$value['repeat_end_date']->mysqlDatetime( FALSE )}{{endif}}'>
</div>
</li>
</ul>
@@ -973,7 +1077,7 @@
</ul>
{{endif}}
</div>]]></template>
<template template_group="view" template_name="comments" template_data="$event" template_location="front" template_app="calendar"><![CDATA[<div class='' data-controller='core.front.core.commentFeed' data-baseURL='{$event->url()}' {{if $event->isLastPage()}}data-lastPage{{endif}} data-feedID='event-{$event->id}' id='comments'>
<template template_group="view" template_name="comments" template_data="$event" template_location="front" template_app="calendar"><![CDATA[<div class='' data-controller='core.front.core.commentFeed' {{if settings.auto_polling_enabled}}data-autoPoll{{endif}} data-baseURL='{$event->url()}' {{if $event->isLastPage()}}data-lastPage{{endif}} data-feedID='event-{$event->id}' id='comments'>
{{if $event->commentPageCount() > 1}}
{$event->commentPagination( array( 'tab' ) )|raw}
<br><br>
@@ -1027,7 +1131,8 @@
{template="prefix" group="global" app="core" params="$event->prefix( TRUE ), $event->prefix()"}
{{endif}}
{{if $event->locked()}}<i class='fa fa-lock'></i> {{endif}}<span itemprop='name'>{$event->title}</span>
{{if $event->locked()}}<i class='fa fa-lock'></i> {{endif}}
{{if $event->mapped('pinned') || $event->mapped('featured') || $event->hidden() === -1 || $event->hidden() === 1}}
{{if $event->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$event->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
@@ -1041,6 +1146,8 @@
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
<span itemprop='name'>{$event->title}</span>
</h1>
<p class='ipsType_normal ipsType_reset'>
<time itemprop='startDate' content='{expression="$event->_start_date->format( 'Y-m-d' )"}'>
@@ -1164,7 +1271,7 @@
<div class='ipsBox'>
<h3 class='ipsType_reset ipsType_sectionHead ipsHide'>{lang="event_rsvp_attendees"}</h3>
<div class='ipsTabs ipsTabs_small ipsClearfix' id='elAttendees{$tabId}' data-ipsTabBar data-ipsTabBar-stretch data-ipsTabBar-contentArea='#elAttendees{$tabId}_content'>
<div class='ipsTabs ipsTabs_small ipsTabs_stretch ipsClearfix' id='elAttendees{$tabId}' data-ipsTabBar data-ipsTabBar-contentArea='#elAttendees{$tabId}_content'>
<a href='#elAttendees{$tabId}' data-action='expandTabs'><i class='fa fa-caret-down'></i></a>
<ul role="tablist">
<li>
@@ -1242,7 +1349,7 @@
</div>
</div>
{{endif}}]]></template>
<template template_group="view" template_name="reviews" template_data="$event" template_location="front" template_app="calendar"><![CDATA[<div data-controller='core.front.core.commentFeed' data-baseURL='{$event->url()}' {{if $event->isLastPage('reviews')}}data-lastPage{{endif}} data-feedID='event-{$event->id}-reviews' id='reviews'>
<template template_group="view" template_name="reviews" template_data="$event" template_location="front" template_app="calendar"><![CDATA[<div data-controller='core.front.core.commentFeed' {{if settings.auto_polling_enabled}}data-autoPoll{{endif}} data-baseURL='{$event->url()}' {{if $event->isLastPage('reviews')}}data-lastPage{{endif}} data-feedID='event-{$event->id}-reviews' id='reviews'>
{{if $event->canReview()}}
{{if $event->locked()}}
<strong class='ipsType_warning'><i class='fa fa-info-circle'></i> {lang="item_locked_can_review"}</strong>
@@ -1296,6 +1403,8 @@
<hr class='ipsHr'>
{$event->reviewPagination( array( 'tab', 'sort' ) )|raw}
{{endif}}
{{elseif !$event->canReview()}}
<p class="ipsType_normal ipsType_light ipsType_reset" data-role="noReviews">{lang="no_reviews"}</p>
{{endif}}
</div>]]></template>
<template template_group="view" template_name="rsvpControls" template_data="$event, $attendees" template_location="front" template_app="calendar"><![CDATA[<!-- Don't use IDs here, this template is called twice in view -->
@@ -1606,11 +1715,11 @@
<span class='ipsCalendarDate_date'>{$event->nextOccurrence( $today, 'startDate' )->mday}</span>
</time>
</div>
<div class='ipsDataItem_main ipsType_break'>
<div class='ipsDataItem_main ipsType_break ipsContained'>
{{if $event->container()->allow_comments && $orientation == 'vertical'}}
<div class="ipsCommentCount ipsPos_right {{if $event->comments === 0}}ipsFaded{{endif}}" data-ipsTooltip title='{lang="replies_number" pluralize="$event->comments"}'>{expression="$event->comments"}</div>
{{endif}}
{{if $event->unread()}}<span class="ipsItemStatus ipsItemStatus_tiny"><i class="fa fa-circle"></i></span> <strong>{{endif}}<a href="{$event->url()}" title='{lang="view_this_event" sprintf="$event->title"}'>{wordbreak="$event->title"}</a>{{if $event->unread()}}</strong>{{endif}}<br>
{{if $event->unread()}}<span class="ipsItemStatus ipsItemStatus_tiny"><i class="fa fa-circle"></i></span> <strong>{{endif}}<a href="{$event->url()}" title='{lang="view_this_event" sprintf="$event->title"}'>{$event->title}</a>{{if $event->unread()}}</strong>{{endif}}<br>
<strong class='ipsType_small'>
{{if $event->nextOccurrence( $today, 'startDate' )}}
{$event->nextOccurrence( $today, 'startDate' )->calendarDate()}{{if !$event->all_day}} {$event->nextOccurrence( $today, 'startDate' )->localeTime( FALSE )} {{endif}}
@@ -1988,7 +2097,9 @@ a.cEvents_event, .cEvents_event a, .cEvents_event.cEvents_empty span {
white-space: nowrap;
overflow: hidden;
}
html[dir="rtl"] a.cEvents_event, .cEvents_event a, .cEvents_event.cEvents_empty span {
html[dir="rtl"] a.cEvents_event,
html[dir="rtl"] .cEvents_event a,
html[dir="rtl"] .cEvents_event.cEvents_empty span {
padding: 0 10px 0 8px;
}
+14 -1
View File
@@ -55,5 +55,18 @@
"100042": "4.0.12",
"100043": "4.0.12.1",
"100044": "4.0.13",
"100045": "4.0.13.1"
"100045": "4.0.13.1",
"101000": "4.1.0 Beta 1",
"101001": "4.1.0 Beta 2",
"101002": "4.1.0 Beta 3",
"101003": "4.1.0 Beta 4",
"101004": "4.1.0 Beta 5",
"101005": "4.1.0 Beta 6",
"101006": "4.1.0 Beta 7",
"101007": "4.1.0 Beta 8",
"101008": "4.1.0 Beta 9",
"101009": "4.1.0 Beta 10",
"101010": "4.1.0",
"101011": "4.1.1",
"101012": "4.1.2"
}
@@ -27,5 +27,19 @@ class _Calendar
/**
* @brief Content Item Classes
*/
public $classes = array( 'IPS\calendar\Event' );
public $classes = array();
/**
* Constructor
*
* @param \IPS\Member|NULL $member If checking access, the member to check for, or NULL to not check access
* @return void
*/
public function __construct( \IPS\Member $member = NULL )
{
if ( $member === NULL or $member->canAccessModule( \IPS\Application\Module::get( 'calendar', 'calendar', 'front' ) ) )
{
$this->classes[] = 'IPS\calendar\Event';
}
}
}
@@ -22,8 +22,18 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* Front Navigation Extension: Calendar
*/
class _Calendar
class _Calendar extends \IPS\core\FrontNavigation\FrontNavigationAbstract
{
/**
* Get Type Title which will display in the AdminCP Menu Manager
*
* @return string
*/
public static function typeTitle()
{
return \IPS\Member::loggedIn()->language()->addToStack('frontnavigation_calendar');
}
/**
* Can access?
*
@@ -31,7 +41,7 @@ class _Calendar
*/
public function canView()
{
return !\IPS\Application::load('calendar')->hide_tab and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'calendar', 'calendar' ) );
return parent::canView() and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'calendar', 'calendar' ) );
}
/**
@@ -63,14 +73,4 @@ class _Calendar
{
return \IPS\Dispatcher::i()->application->directory === 'calendar';
}
/**
* Children
*
* @return array
*/
public function children()
{
return array();
}
}
@@ -185,7 +185,7 @@ class _event extends \IPS\Content\Controller
}
/* We delete either way at this point, because even if we select a different action we have to remove any existing RSVP preference */
\IPS\Db::i()->delete( 'calendar_event_rsvp', array( 'rsvp_event_id=? AND rsvp_member_id=?', $this->event->id, \IPS\Member::loggedIn()->member_id ) );
\IPS\Db::i()->delete( 'calendar_event_rsvp', array( 'rsvp_event_id=? AND rsvp_member_id=?', $this->event->id, (int) \IPS\Member::loggedIn()->member_id ) );
if( \IPS\Request::i()->action == 'leave' )
{
@@ -229,7 +229,7 @@ class _event extends \IPS\Content\Controller
\IPS\Db::i()->insert( 'calendar_event_rsvp', array(
'rsvp_event_id' => $this->event->id,
'rsvp_member_id' => \IPS\Member::loggedIn()->member_id,
'rsvp_member_id' => (int) \IPS\Member::loggedIn()->member_id,
'rsvp_date' => time(),
'rsvp_response' => (int) $_go
) );
@@ -239,4 +239,16 @@ class _event extends \IPS\Content\Controller
\IPS\Output::i()->redirect( $this->event->url(), $message );
}
/**
* Edit Item
*
* @return void
*/
protected function edit()
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_submit.js', 'calendar', 'front' ) );
return parent::edit();
}
}
@@ -495,21 +495,25 @@ class _view extends \IPS\Dispatcher\Controller
if( $values = $form->values() )
{
\IPS\Request::i()->view = 'day';
if( \IPS\Request::i()->goto )
{
\IPS\Request::i()->y = null;
\IPS\Request::i()->m = null;
\IPS\Request::i()->d = null;
\IPS\Request::i()->w = null;
$dateToGoTo = \IPS\DateTime::create();
}
else
{
\IPS\Request::i()->y = $values['jump_to']->format('Y');
\IPS\Request::i()->m = $values['jump_to']->format('m');
\IPS\Request::i()->d = $values['jump_to']->format('j');
$dateToGoTo = $values['jump_to'];
}
if ( $this->_calendar )
{
$url = \IPS\Http\Url::internal( "app=calendar&module=calendar&controller=view&view=day&id={$this->_calendar->_id}&y={$dateToGoTo->format('Y')}&m={$dateToGoTo->format('m')}&d={$dateToGoTo->format('j')}", 'front', 'calendar_calday', $this->_calendar->title_seo );
}
else
{
$url = \IPS\Http\Url::internal( "app=calendar&module=calendar&controller=view&view=day&y={$dateToGoTo->format('Y')}&m={$dateToGoTo->format('m')}&d={$dateToGoTo->format('j')}", 'front', 'calendar_day' );
}
\IPS\Output::i()->redirect( $url );
}
return $form;
@@ -107,6 +107,3 @@ $SQL[] = "INSERT INTO cal_events SELECT event_id, event_calendar_id, event_membe
event_recurring, FROM_UNIXTIME(event_unix_from), CASE WHEN event_unix_to > 0 THEN FROM_UNIXTIME(event_unix_to) ELSE NULL END, '', 0, 0, 0, 0, MD5( CONCAT( event_id, event_title ) ), 0, 1 FROM " . \IPS\Db::i()->prefix . "cal_events_bak;";
$SQL[] = "DROP TABLE cal_events_bak;";
$SQL[] = "ALTER TABLE cal_events ADD event_all_day TINYINT NOT NULL DEFAULT '0';";
$SQL[] = "UPDATE cal_events SET event_all_day=1 WHERE TIME(event_start_date) = '00:00:00';";
@@ -0,0 +1,4 @@
<?php
$SQL[] = "ALTER TABLE cal_events ADD event_all_day TINYINT NOT NULL DEFAULT '0';";
$SQL[] = "UPDATE cal_events SET event_all_day=1 WHERE TIME(event_start_date) = '00:00:00';";
@@ -0,0 +1,38 @@
<?php
/**
* @brief 4.0.0 Upgrade Code
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Calendar
* @since 8 October 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\calendar\setup\upg_32005;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* 4.0.0 Upgrade Code
*/
class _Upgrade
{
/**
* Conversion from 3.0
*
* @return array If returns TRUE, upgrader will proceed to next step. If it returns any other value, it will set this as the value of the 'extra' GET parameter and rerun this step (useful for loops)
*/
public function step1()
{
\IPS\core\Setup\Upgrade::runLegacySql( 'calendar', 32005 );
return TRUE;
}
}
@@ -65,7 +65,7 @@ class _Upgrade
{
foreach( \IPS\Db::i()->select( '*', 'calendar_calendars' ) as $calendar )
{
\IPS\Lang::saveCustom( 'calendar', "calendar_calendar_{$calendar['cal_id']}", html_entity_decode( $calendar['cal_title'], ENT_QUOTES, 'UTF-8' ) );
\IPS\Lang::saveCustom( 'calendar', "calendar_calendar_{$calendar['cal_id']}", \IPS\Text\Parser::utf8mb4SafeDecode( $calendar['cal_title'] ) );
}
\IPS\Db::i()->dropColumn( 'calendar_calendars', 'cal_title' );
@@ -185,21 +185,21 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
* @brief Cached URL
*/
protected $_url = NULL;
/**
* Get URL
*
* @return \IPS\Http\Url
* @brief URL Base
*/
public function url()
{
if( $this->_url === NULL )
{
$this->_url = \IPS\Http\Url::internal( "app=calendar&module=calendar&controller=view&id={$this->_id}", 'front', 'calendar_calendar', $this->title_seo );
}
return $this->_url;
}
public static $urlBase = 'app=calendar&module=calendar&controller=view&id=';
/**
* @brief URL Base
*/
public static $urlTemplate = 'calendar_calendar';
/**
* @brief SEO Title Column
*/
public static $seoTitleColumn = 'title_seo';
/**
* [ActiveRecord] Delete Record
+14 -2
View File
@@ -425,11 +425,11 @@ class _Date extends \IPS\DateTime
{
if( \IPS\Settings::i()->calendar_date_format == -1 AND \IPS\Settings::i()->calendar_date_format_custom )
{
return \IPS\Member::loggedIn()->language()->convertString( strftime( \IPS\Settings::i()->calendar_date_format_custom, $this->getTimestamp() + $this->getTimezone()->getOffset( $this ) ) );
return \IPS\Member::loggedIn()->language()->convertString( strftime( \IPS\Settings::i()->calendar_date_format_custom, $this->getTimestamp() + $this->offset ) );
}
elseif( isset( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ] ) )
{
return \IPS\Member::loggedIn()->language()->convertString( strftime( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ], $this->getTimestamp() + $this->getTimezone()->getOffset( $this ) ) );
return \IPS\Member::loggedIn()->language()->convertString( strftime( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ], $this->getTimestamp() + $this->offset ) );
}
else
{
@@ -731,4 +731,16 @@ class _Date extends \IPS\DateTime
return NULL;
}
/**
* Format the time according to the user's locale (without the date)
*
* @param bool $seconds If TRUE, will include seconds
* @param bool $minutes If TRUE, will include minutes
* @return string
*/
public function localeTime( $seconds=TRUE, $minutes=TRUE )
{
return \IPS\Member::loggedIn()->language()->convertString( strftime( $this->localeTimeFormat( $seconds, $minutes ), $this->getTimestamp() + $this->offset ) );
}
}
@@ -105,4 +105,37 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
{
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core' ), 'commentRows' );
}
/**
* Get snippet HTML for search result display
*
* @param array $indexData Data from the search index
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @param array $reputationData Array of people who have given reputation and the reputation they gave
* @param int|NULL $reviewRating If this is a review, the rating
* @param string $view 'expanded' or 'condensed'
* @return callable
*/
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $view )
{
$startDate = \IPS\calendar\Date::parseTime( $itemData['event_start_date'], $itemData['event_all_day'] ? FALSE : TRUE );
$endDate = $itemData['event_end_date'] ? \IPS\calendar\Date::parseTime( $itemData['event_end_date'], $itemData['event_all_day'] ? FALSE : TRUE ) : NULL;
$nextOccurance = $startDate;
if ( $itemData['event_recurring'] )
{
$occurances = \IPS\calendar\Event::_findOccurances( $startDate, $endDate, $startDate->adjust( "-1 month" ), $startDate->adjust( "+2 years" ), \IPS\calendar\Icalendar\ICSParser::parseRrule( $itemData['event_recurring'] ) );
foreach( $occurances as $occurrence )
{
if( $occurrence['startDate'] AND $occurrence['startDate']->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) )
{
$nextOccurance = $occurrence['startDate'];
break;
}
}
}
return \IPS\Theme::i()->getTemplate( 'global', 'calendar', 'front' )->searchResultCommentSnippet( $indexData, $nextOccurance, $startDate, $endDate, $itemData['event_all_day'], $reviewRating, $view == 'condensed' );
}
}
+150 -44
View File
@@ -145,6 +145,21 @@ class _Event extends \IPS\Content\Item implements
const RSVP_YES = 1;
const RSVP_MAYBE = 2;
/**
* Columns needed to query for search result / stream view
*
* @return array
*/
public static function basicDataColumns()
{
$return = parent::basicDataColumns();
$return[] = 'event_recurring';
$return[] = 'event_start_date';
$return[] = 'event_end_date';
$return[] = 'event_all_day';
return $return;
}
/**
* Set the title
*
@@ -308,10 +323,27 @@ class _Event extends \IPS\Content\Item implements
//return $results;
}
/* Now figure out when this event occurs on */
/* Return the results we found after storing them */
$this->parsedOccurrences = static::_findOccurances( $this->_start_date, $this->_end_date, $startDate, $endDate, $recurringData );
return $this->parsedOccurrences;
}
/**
* Get occurances
*
* @param \IPS\calendar\Date $eventStart Event start date
* @param \IPS\calendar\Date $eventEnd Event end date
* @param \IPS\calendar\Date $startDate Date to start from
* @param \IPS\calendar\Date $endDate Date to end at
* @param array $recurringData Reccurance data
*/
public static function _findOccurances( $eventStart, $eventEnd, $startDate, $endDate, $recurringData )
{
$instances = array();
$occurrences = 0;
$keyword = NULL;
$results = array();
switch( $recurringData['event_repeats'] )
{
@@ -338,8 +370,8 @@ class _Event extends \IPS\Content\Item implements
}
else
{
$date = $this->_start_date;
$eDate = $this->_end_date;
$date = $eventStart;
$eDate = $eventEnd;
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
( $eDate !== NULL AND $eDate->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
@@ -348,8 +380,18 @@ class _Event extends \IPS\Content\Item implements
{
$results[] = array( 'startDate' => $date, 'endDate' => $eDate );
}
$nextDay = current( $_repeatDays );
/* Figure out which of teh days is next. For example, if the start date is a Wednesday, and the
event repeats every Monday and Friday, we need to start with Friday (not Monday) because that's
when the first occurance is */
$nextTimes = array();
foreach ( $_repeatDays as $repeatDay )
{
$nextTimes[ $repeatDay ] = $date->adjust( "next {$repeatDay}" )->getTimestamp();
}
asort( $nextTimes );
$nextTimes = array_keys( $nextTimes );
$nextDay = array_shift( $nextTimes );
/* Do we have an occurrences limit? */
if( $recurringData['repeat_end_occurrences'] )
@@ -445,8 +487,8 @@ class _Event extends \IPS\Content\Item implements
/* Normal recurrence checks */
if( $keyword !== NULL )
{
$date = $this->_start_date;
$eDate = $this->_end_date;
$date = $eventStart;
$eDate = $eventEnd;
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
( $eDate !== NULL AND $eDate->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
@@ -496,7 +538,7 @@ class _Event extends \IPS\Content\Item implements
/* Recurs indefinitely... the most fun type... */
else
{
while( $date->mysqlDatetime( FALSE ) < $endDate->mysqlDatetime( FALSE ) )
while( $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) )
{
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
( $eDate !== NULL AND $eDate->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
@@ -511,11 +553,8 @@ class _Event extends \IPS\Content\Item implements
}
}
}
/* Return the results we found after storing them */
$this->parsedOccurrences = $results;
return $this->parsedOccurrences;
return $results;
}
/**
@@ -716,29 +755,21 @@ class _Event extends \IPS\Content\Item implements
* @brief Cached URLs
*/
protected $_url = array();
/**
* Get URL
*
* @param string|NULL $action Action
* @return \IPS\Http\Url
*/
public function url( $action=NULL )
{
$_key = md5( $action );
if( !isset( $this->_url[ $_key ] ) )
{
$this->_url[ $_key ] = \IPS\Http\Url::internal( "app=calendar&module=calendar&controller=event&id={$this->id}", 'front', 'calendar_event', $this->title_seo );
if ( $action )
{
$this->_url[ $_key ] = $this->_url[ $_key ]->setQueryString( 'do', $action );
}
}
return $this->_url[ $_key ];
}
/**
* @brief URL Base
*/
public static $urlBase = 'app=calendar&module=calendar&controller=event&id=';
/**
* @brief URL Base
*/
public static $urlTemplate = 'calendar_event';
/**
* @brief SEO Title Column
*/
public static $seoTitleColumn = 'title_seo';
/**
* Get URL for last comment page
@@ -772,6 +803,40 @@ class _Event extends \IPS\Content\Item implements
return array( \IPS\Theme::i()->getTemplate( 'global', 'calendar' ), 'rows' );
}
/**
* HTML to manage an item's follows
*
* @return callable
*/
public static function manageFollowRows()
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'calendar.css', 'calendar' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'calendar_responsive.css', 'calendar' ) );
return array( \IPS\Theme::i()->getTemplate( 'global', 'calendar', 'front' ), 'manageFollowRow' );
}
/**
* Are comments supported by this class?
*
* @param \IPS\Member\NULL $member The member to check for or NULL fto not check permission
* @return int
*/
public static function supportsComments( \IPS\Member $member = NULL )
{
return parent::supportsComments() and ( !$member or \IPS\calendar\Calendar::countWhere( 'read', $member, array( 'cal_allow_comments=1' ) ) );
}
/**
* Are reviews supported by this class?
*
* @param \IPS\Member\NULL $member The member to check for or NULL to not check permission
* @return int
*/
public static function supportsReviews( \IPS\Member $member = NULL )
{
return parent::supportsReviews() and ( !$member or \IPS\calendar\Calendar::countWhere( 'read', $member, array( 'cal_allow_reviews=1' ) ) );
}
/**
* Get available comment/review tabs
*
@@ -1009,12 +1074,12 @@ class _Event extends \IPS\Content\Item implements
/* Cover photo and location */
$return['header'] = new \IPS\Helpers\Form\Upload( 'event_cover_photo', ( $item AND $item->cover_photo ) ? \IPS\File::get( 'calendar_Events', $item->cover_photo ) : NULL, FALSE, array( 'image' => TRUE, 'storageExtension' => 'calendar_Events' ) );
$return['location'] = new \IPS\Helpers\Form\Address( 'event_location', ( $item AND $item->location ) ? \IPS\GeoLocation::buildFromJson( $item->location ) : NULL, FALSE, array( 'minimize' => TRUE ) );
$return['location'] = new \IPS\Helpers\Form\Address( 'event_location', ( $item AND $item->location ) ? \IPS\GeoLocation::buildFromJson( $item->location ) : NULL, FALSE, array( 'minimize' => TRUE, 'requireFullAddress' => FALSE ) );
/* Gallery album association */
if( \IPS\Application::appIsEnabled( 'gallery' ) )
{
$return['album'] = new \IPS\Helpers\Form\Node( 'event_album', ( $item AND $item->event_album ) ? $item->event_album : NULL, FALSE, array(
$return['album'] = new \IPS\Helpers\Form\Node( 'event_album', ( $item AND $item->album ) ? $item->album : NULL, FALSE, array(
'url' => \IPS\Http\Url::internal( 'app=calendar&module=calendar&controller=submit', 'front', 'calendar_submit' ),
'class' => 'IPS\gallery\Album',
'permissionCheck' => 'add',
@@ -1049,7 +1114,7 @@ class _Event extends \IPS\Content\Item implements
* @return void
*/
public function processForm( $values )
{
{
/* Anything but Chrome, basically, falls back to a text input and submitter might submit 22.00 instead of 22:00 */
if( isset( $values['event_dates']['start_time'] ) )
{
@@ -1183,11 +1248,11 @@ class _Event extends \IPS\Content\Item implements
/**
* Retrieve events to show based on a provided start and end date, optionally filtering by a supplied calendar
*
* @param \IPS\calendar\Date $startDate Date to start from
* @param \IPS\calendar\Date|NULL $endDate Cut off date for events. NULL accepted as a possible value only if $formatEvents is set to FALSE.
* @param \IPS\calendar\Calendar|NULL $calendar Calendar to filter by
* @param int|null $limit Maximum number of events to return (only supported when not formatting events)
* @param bool $formatEvents Whether or not to format events into a structured array
* @param \IPS\calendar\Date $startDate Date to start from
* @param \IPS\calendar\Date|NULL $endDate Cut off date for events. NULL accepted as a possible value only if $formatEvents is set to FALSE.
* @param \IPS\calendar\Calendar|NULL|array $calendar Calendar to filter by
* @param int|null $limit Maximum number of events to return (only supported when not formatting events)
* @param bool $formatEvents Whether or not to format events into a structured array
* @return \IPS\Patterns\ActiveRecordIterator
* @throws \InvalidArgumentException
* @see \IPS\Content\_Item::getItemsWithPermission()
@@ -1198,7 +1263,15 @@ class _Event extends \IPS\Content\Item implements
if( $calendar !== NULL )
{
$where[] = array( 'event_calendar_id=?', (int) $calendar->_id );
if ( is_array( $calendar ) )
{
$where[] = array( \IPS\Db::i()->in( 'event_calendar_id', $calendar ) );
}
else
{
$where[] = array( 'event_calendar_id=?', (int) $calendar->_id );
}
}
if( $endDate === NULL AND $formatEvents === TRUE )
@@ -1475,4 +1548,37 @@ class _Event extends \IPS\Content\Item implements
{
return \IPS\Theme::i()->getTemplate( 'global', 'calendar' )->embedCalendar_event( $this, $this->url()->setQueryString( $params ) );
}
/**
* Get snippet HTML for search result display
*
* @param array $indexData Data from the search index
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @param array $reputationData Array of people who have given reputation and the reputation they gave
* @param int|NULL $reviewRating If this is a review, the rating
* @param string $view 'expanded' or 'condensed'
* @return callable
*/
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $view )
{
$startDate = \IPS\calendar\Date::parseTime( $itemData['event_start_date'], $itemData['event_all_day'] ? FALSE : TRUE );
$endDate = $itemData['event_end_date'] ? \IPS\calendar\Date::parseTime( $itemData['event_end_date'], $itemData['event_all_day'] ? FALSE : TRUE ) : NULL;
$nextOccurance = $startDate;
if ( $itemData['event_recurring'] )
{
$occurances = \IPS\calendar\Event::_findOccurances( $startDate, $endDate, $startDate->adjust( "-1 month" ), $startDate->adjust( "+2 years" ), \IPS\calendar\Icalendar\ICSParser::parseRrule( $itemData['event_recurring'] ) );
foreach( $occurances as $occurrence )
{
if( $occurrence['startDate'] AND $occurrence['startDate']->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) )
{
$nextOccurance = $occurrence['startDate'];
break;
}
}
}
return \IPS\Theme::i()->getTemplate( 'global', 'calendar', 'front' )->searchResultEventSnippet( $indexData, $itemData, $nextOccurance, $startDate, $endDate, $itemData['event_all_day'], $view == 'condensed' );
}
}
@@ -109,4 +109,21 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
{
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core' ), 'commentRows' );
}
/**
* Get snippet HTML for search result display
*
* @param array $indexData Data from the search index
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @param array $reputationData Array of people who have given reputation and the reputation they gave
* @param int|NULL $reviewRating If this is a review, the rating
* @param string $view 'expanded' or 'condensed'
* @return callable
*/
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, array $containerData = NULL, array $reputationData, $reviewRating, $view )
{
return \IPS\calendar\Event\Comment::searchResultSnippet( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $view );
}
}
@@ -383,7 +383,7 @@ class _ICSParser
{
try
{
$eventId = \IPS\Db::i()->select( 'import_event_id', 'calendar_import_map', array( 'import_guid=?', $event['uid'] ) )->first();
$eventId = \IPS\Db::i()->select( 'import_event_id', 'calendar_import_map', array( array( 'import_guid=? and import_feed_id=?', $event['uid'], $this->feed->id ) ) )->first();
try
{
@@ -696,8 +696,8 @@ class _ICSParser
}
else
{
$output .= "DTSTART;TZID=Europe/London:" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
$output .= "DTEND;TZID=Europe/London:" . $event->_end_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
$output .= "DTSTART;" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
$output .= "DTEND;" . $event->_end_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
}
}
else
@@ -708,7 +708,7 @@ class _ICSParser
}
else
{
$output .= "DTSTART;TZID=Europe/London:" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
$output .= "DTSTART;" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
}
}
@@ -1124,8 +1124,11 @@ class _ICSParser
break;
case 'ORGANIZER':
$line = explode( ':', $_data );
$_event['organizer'] = array( 'name' => str_replace( 'CN=', '', $line[0] ), 'email' => $line[1] );
if ( $_data )
{
$line = explode( ':', $_data );
$_event['organizer'] = array( 'name' => str_replace( 'CN=', '', $line[0] ), 'email' => $line[1] );
}
break;
case 'ATTENDEE':
@@ -50,13 +50,37 @@ class _recentReviews extends \IPS\Widget\PermissionCache
if ( $form === null )
{
$form = new \IPS\Helpers\Form;
}
}
/* Container */
$form->add( new \IPS\Helpers\Form\Node( 'widget_calendar', isset( $this->configuration['widget_calendar'] ) ? $this->configuration['widget_calendar'] : 0, FALSE, array(
'class' => '\IPS\calendar\Calendar',
'zeroVal' => 'all',
'permissionCheck' => 'view',
'multiple' => true
) ) );
$form->add( new \IPS\Helpers\Form\Number( 'review_count', isset( $this->configuration['review_count'] ) ? $this->configuration['review_count'] : 5, TRUE ) );
return $form;
}
/**
* Ran before saving widget configuration
*
* @param array $values Values from form
* @return array
*/
public function preConfig( $values )
{
if ( is_array( $values['widget_calendar'] ) )
{
$values['widget_calendar'] = array_keys( $values['widget_calendar'] );
}
return $values;
}
/**
* Render a widget
*
@@ -64,12 +88,14 @@ class _recentReviews extends \IPS\Widget\PermissionCache
*/
public function render()
{
if( !\IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'calendar', 'calendar' ) ) )
$where = array();
if ( ! empty( $this->configuration['widget_calendar'] ) )
{
return '';
$where['item'][] = array( \IPS\Db::i()->in( 'event_calendar_id', $this->configuration['widget_calendar'] ) );
}
$reviews = \IPS\calendar\Event\Review::getItemsWithPermission( array(), NULL, ( isset( $this->configuration['review_count'] ) AND $this->configuration['review_count'] > 0 ) ? $this->configuration['review_count'] : 5 );
$reviews = \IPS\calendar\Event\Review::getItemsWithPermission( $where, NULL, ( isset( $this->configuration['review_count'] ) AND $this->configuration['review_count'] > 0 ) ? $this->configuration['review_count'] : 5 );
return $this->output( $reviews );
}
@@ -44,7 +44,26 @@ class _upcomingEvents extends \IPS\Widget\PermissionCache
* @note We allow this cache to be valid for 12 hours
*/
public $cacheExpiration = 43200;
/**
* Constructor
*
* @param String $uniqueKey Unique key for this specific instance
* @param array $configuration Widget custom configuration
* @param null|string|array $access Array/JSON string of executable apps (core=sidebar only, content=IP.Content only, etc)
* @param null|string $orientation Orientation (top, bottom, right, left)
* @param boolean $allowReuse If true, when the block is used, it will remain in the sidebar so it can be used again.
* @param string $menuStyle Menu is a drop down menu, modal is a bigger modal panel.
* @return void
*/
public function __construct( $uniqueKey, array $configuration, $access=null, $orientation=null )
{
parent::__construct( $uniqueKey, $configuration, $access, $orientation );
/* We need to adjust for timezone too */
$this->cacheKey = "widget_{$this->key}_" . $this->uniqueKey . '_' . md5( json_encode( $configuration ) . "_" . \IPS\Member::loggedIn()->language()->id . "_" . \IPS\Member::loggedIn()->skin . "_" . json_encode( \IPS\Member::loggedIn()->groups ) . "_" . $orientation . \IPS\Member::loggedIn()->timezone );
}
/**
* Initialize this widget
*
@@ -70,12 +89,36 @@ class _upcomingEvents extends \IPS\Widget\PermissionCache
$form = new \IPS\Helpers\Form;
}
/* Container */
$form->add( new \IPS\Helpers\Form\Node( 'widget_calendar', isset( $this->configuration['widget_calendar'] ) ? $this->configuration['widget_calendar'] : 0, FALSE, array(
'class' => '\IPS\calendar\Calendar',
'zeroVal' => 'all',
'permissionCheck' => 'view',
'multiple' => true
) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'auto_hide', isset( $this->configuration['auto_hide'] ) ? $this->configuration['auto_hide'] : FALSE, FALSE ) );
$form->add( new \IPS\Helpers\Form\Number( 'days_ahead', isset( $this->configuration['days_ahead'] ) ? $this->configuration['days_ahead'] : NULL, TRUE, array( 'unlimited' => -1 ) ) );
$form->add( new \IPS\Helpers\Form\Number( 'maximum_count', isset( $this->configuration['maximum_count'] ) ? $this->configuration['maximum_count'] : 5, TRUE, array( 'unlimited' => -1 ) ) );
return $form;
}
/**
* Ran before saving widget configuration
*
* @param array $values Values from form
* @return array
*/
public function preConfig( $values )
{
if ( is_array( $values['widget_calendar'] ) )
{
$values['widget_calendar'] = array_keys( $values['widget_calendar'] );
}
return $values;
}
/**
* Render a widget
*
@@ -97,8 +140,15 @@ class _upcomingEvents extends \IPS\Widget\PermissionCache
{
$endDate = $_today->adjust( "+" . $this->configuration['days_ahead'] . " days" );
}
$events = \IPS\calendar\Event::retrieveEvents( $_today, $endDate, NULL, ( isset( $this->configuration['maximum_count'] ) AND $this->configuration['maximum_count'] > 0 ) ? $this->configuration['maximum_count'] : 5, FALSE );
$calendars = NULL;
if ( ! empty( $this->configuration['widget_calendar'] ) )
{
$calendars = $this->configuration['widget_calendar'];
}
$events = \IPS\calendar\Event::retrieveEvents( $_today, $endDate, $calendars, ( isset( $this->configuration['maximum_count'] ) AND $this->configuration['maximum_count'] > 0 ) ? $this->configuration['maximum_count'] : 5, FALSE );
/* Auto hiding? */
if( !count($events) AND isset( $this->configuration['auto_hide'] ) AND $this->configuration['auto_hide'] )
+52
View File
@@ -41,4 +41,56 @@ class _Application extends \IPS\Application
{
return 'comment';
}
/**
* Is chat online? Returns error message if not
*
* @return string|TRUE
*/
public function offlineMessage()
{
if( \IPS\Settings::i()->ipschat_online )
{
$times = explode( ',', \IPS\Settings::i()->ipschat_online );
if( count( $times ) AND $times[0] )
{
/* Do we need to adjust the time zone? */
if( isset( $times[2] ) AND $times[2] != \IPS\Member::loggedIn()->timezone )
{
$start = new \IPS\DateTime( '2015-01-01 ' . $times[0], new \DateTimeZone( $times[2] ) );
$start->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
$times[0] = $start->format( 'H:i' );
$end = new \IPS\DateTime( '2015-01-01 ' . $times[1], new \DateTimeZone( $times[2] ) );
$end->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
$times[1] = $end->format( 'H:i' );
}
$currentTime = new \IPS\DateTime( NULL, new \DateTimeZone( ( isset( $times[2] ) ) ? $times[2] : \IPS\Member::loggedIn()->timezone ) );
$currentTime->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
$currentTime = $currentTime->format( 'H:i' );
/* Convert times to floats, as that is simple to compare */
$start = str_replace( ':', '.', $times[0] );
$end = str_replace( ':', '.', $times[1] );
$currentTime = str_replace( ':', '.', $currentTime );
if( $end > $start )
{
if( !( $currentTime >= $start ) OR !( $currentTime < $end ) )
{
return \IPS\Member::loggedIn()->language()->addToStack( 'chat_currently_offline', FALSE, array( 'sprintf' => $start ) );
}
}
else
{
if( !( $currentTime >= $start ) AND $currentTime >= $end )
{
return \IPS\Member::loggedIn()->language()->addToStack( 'chat_currently_offline', FALSE, array( 'sprintf' => $start ) );
}
}
}
}
}
}
+6 -6
View File
@@ -1,16 +1,16 @@
{
"chat": {
"logs": {
"tab": "community",
"controller": "logs",
"do": "",
"restriction": "logs_manage"
},
"settings": {
"tab": "community",
"controller": "settings",
"do": "",
"restriction": "settings_manage"
},
"logs": {
"tab": "community",
"controller": "logs",
"do": "",
"restriction": "logs_manage"
}
}
}
+57 -15
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<javascript app="chat">
<file javascript_app="chat" javascript_location="front" javascript_path="controllers/chat" javascript_name="ips.chat.main.js" javascript_type="controller" javascript_version="100045" javascript_position="1000050"><![CDATA[/**
<file javascript_app="chat" javascript_location="front" javascript_path="controllers/chat" javascript_name="ips.chat.main.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -52,12 +52,29 @@
},
/**
* Setup method
* Setup wrapper method
*
* @returns {void}
*/
setup: function () {
//return;
var self = this;
if( window.btoa && window.atob ){
this._doSetup();
} else {
// If bas64 isn't supported in the browser (< IE10), then load a polyfill before continuing
ips.loader.get( ['chat/interface/base64/base64.js'] ).then( function () {
self._doSetup();
});
}
},
/**
* Performs setup tasks
*
* @returns {void}
*/
_doSetup: function () {
var self = this;
this._setUpMainPanel();
@@ -331,7 +348,8 @@
* @returns {void}
*/
_createBadge: function () {
$('.elNavigation_app_chat_Chat').append( $('<span/>').addClass('ipsNotificationCount').text('0') );
// This is now added with a hook and doesn't need to be done here
//$('.elNavigation_app_chat_Chat').append( $('<span/>').addClass('ipsNotificationCount').text('0') );
},
/**
@@ -457,7 +475,8 @@
*/
_ping: function () {
var url = '?app=chat&module=chat&controller=action&do=ping';
var self = this;
// Load the mini profile to show in the sidebar
ips.getAjax()( url, {
data: {
@@ -466,6 +485,17 @@
})
.done( function (response) {
// We don't need to do anything
})
.fail(function(response){
if ( response.responseJSON.message ) {
var containers = self._getAllStorageContainers();
containers.append( ips.templates.render('chat.system', {
text: response.responseJSON.message,
date: self._getChatTime( self._getCurrentTime() )
}));
self._kicked = true;
self._scrollToBottom( self._activeTab );
}
});
},
@@ -809,8 +839,8 @@
this._checkInactivity( curtime );
if( this._kicked ){
clearTimeout( this._poller );
clearTimeout( this._updater );
clearInterval( this._poller );
clearInterval( this._updater );
}
// If current time - last polled time is less than the polling timeperiod,
@@ -1319,7 +1349,7 @@
this.scope.find('[data-role="onlineChatters"]').html( ips.pluralize( ips.getString('usersChatting'), total ) );
// Update global chat tab
$('.elNavigation_app_chat_Chat .ipsNotificationCount').text( total );
$('.ipsNavBar_primary [data-navapp="chat"] .ipsNotificationCount').text( total );
},
/**
@@ -1348,9 +1378,9 @@
_unCleanMessage: function (message) {
return message
.replace( /__PS__/g, "+" )
.replace( /__E__/g, "=" )
.replace( /__P__/g, "%" )
.replace( /__A__/g, "&" )
.replace( /__E__/g, "=" )
.replace( /__C__/g, "," )
.replace( /__N__/g, "<br />" );
},
@@ -1374,10 +1404,20 @@
// @todo this line still needed?
message = message.replace( '!', '&#33;' );
_.each( ips.getSetting('chatEmoticons'), function (url, emoticon) {
var img = "$1<img src='" + url + "'>$2";
_.each( ips.getSetting('chatEmoticons'), function (url, emoticon) {
var img = $('<img/>').attr({ 'src': url['image'], 'data-emoticon': 'true' });
if ( url['width'] ) {
img.attr( 'width', url['width'] );
}
if ( url['height'] ) {
img.attr( 'height', url['width'] );
}
if ( url['image_2x'] ) {
img.attr( 'srcset', url['image_2x'] );
}
img = "$1" + $('<div/>').append( img ).html() + "$2";
var regexp = new RegExp( "(^|\\s)" + self._escapeRegex( emoticon ) + "(\\s|$)", "gi" );
while( message.match( regexp ) ){
message = message.replace( regexp, img );
}
@@ -1657,7 +1697,7 @@
var indexOfURL = text.indexOf( url, lastPos );
var returnURL = url;
if( text.substring( indexOfURL, indexOfURL - 5) !== "src='" ){
if( text.substring( indexOfURL, indexOfURL - 5) !== 'src="' && text.substring( indexOfURL, indexOfURL - 8) !== 'srcset="' ){
returnURL = '<a href="' + url + '" target="_blank">' + url + '</a>';
}
@@ -1744,7 +1784,9 @@
msgDetails[2] = _details.prefix.replace( /__DBQ__/g, '"' ) + msgDetails[2] + _details.suffix.replace( /__DBQ__/g, '"' );
}
var tab = this.scope.find('#elChatTabs [data-user="' + msgDetails[2] + '"]')
// https://community.invisionpower.com/4bugtrack/active-reports/chat-tabs-with-html-in-group-name-r8351/
// This line isn't actually used and was causing the error.
//var tab = this.scope.find('#elChatTabs [data-user="' + msgDetails[2] + '"]')
state.alsoTo = details[1];
@@ -1837,7 +1879,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="chat" javascript_location="front" javascript_path="templates" javascript_name="ips.templates.chat.js" javascript_type="template" javascript_version="100045" javascript_position="1000100"><![CDATA[ips.templates.set('chat.tabs.tab', " \
<file javascript_app="chat" javascript_location="front" javascript_path="templates" javascript_name="ips.templates.chat.js" javascript_type="template" javascript_version="101012" javascript_position="1000100"><![CDATA[ips.templates.set('chat.tabs.tab', " \
<li role='presentation' data-roomID='{{roomID}}'>\
<a href='#' role='tab' id='{{roomID}}' class='ipsFaded_withHover ipsTabs_item ipsType_blendLinks {{#active}}ipsTabs_activeItem{{/active}}' aria-selected='false'>\
{{roomTitle}} {{#close}}&nbsp;<span class='ipsFaded ipsFaded_more' data-action='closeTab' data-ipsTooltip title='{{#lang}}closeThisTab{{/lang}}'><i class='fa fa-times'></i></span>{{/close}}\
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<language>
<app key="chat" version="100045">
<app key="chat" version="101012">
<word key="__app_chat" js="0">Chat</word>
<word key="frontnavigation_chat" js="0">Chat</word>
<word key="chat_title" js="0">Chat</word>
+5 -3
View File
@@ -50,7 +50,7 @@
</li>
<li>
{{$leave = \IPS\Request::i()->_popup ? '&_popup=' . \IPS\Request::i()->_popup : '';}}
<a href='{url="app=chat&module=chat&controller=view&do=leave{$leave}" seoTemplate="chat" csrf="true"}' class='ipsPos_right ipsButton ipsButton_verySmall ipsButton_overlaid' data-action='leaveChat' data-ipsTooltip title='{lang="chat_leave_room"}'>{lang="chat_leave_room"}</a>
<a href='{url="app=chat&module=chat&controller=view&do=leave{$leave}" seoTemplate="chat" csrf="true"}' class='ipsPos_right ipsButton ipsButton_verySmall ipsButton_overlaid' data-action='leaveChat'>{lang="chat_leave_room"}</a>
</li>
</ul>
<a href="#elChatTabs" data-action="expandTabs"><i class="fa fa-caret-down"></i></a>
@@ -74,7 +74,7 @@
</li>
<li>
{{$leave = \IPS\Request::i()->_popup ? '&_popup=' . \IPS\Request::i()->_popup : '';}}
<a href='{url="app=chat&module=chat&controller=view&do=leave{$leave}" seoTemplate="chat" csrf="true"}' class='ipsPos_right ipsButton ipsButton_verySmall ipsButton_light' data-action='leaveChat' data-ipsTooltip title='{lang="chat_leave_room"}'>{lang="chat_leave_room"}</a>
<a href='{url="app=chat&module=chat&controller=view&do=leave{$leave}" seoTemplate="chat" csrf="true"}' class='ipsPos_right ipsButton ipsButton_verySmall ipsButton_light' data-action='leaveChat'>{lang="chat_leave_room"}</a>
</li>
</ul>
</div>
@@ -169,7 +169,9 @@
<a href='#'>{lang="ipchat_ban"}</a>
</li>
{{endif}}
<li class='ipsMenu_sep'><hr></li>
{{if $data['forumUserID']}}
<li class='ipsMenu_sep'><hr></li>
{{endif}}
{{endif}}
{{if $data['forumUserID']}}
<li class='ipsMenu_item'>
+14 -1
View File
@@ -85,5 +85,18 @@
"100042": "4.0.12",
"100043": "4.0.12.1",
"100044": "4.0.13",
"100045": "4.0.13.1"
"100045": "4.0.13.1",
"101000": "4.1.0 Beta 1",
"101001": "4.1.0 Beta 2",
"101002": "4.1.0 Beta 3",
"101003": "4.1.0 Beta 4",
"101004": "4.1.0 Beta 5",
"101005": "4.1.0 Beta 6",
"101006": "4.1.0 Beta 7",
"101007": "4.1.0 Beta 8",
"101008": "4.1.0 Beta 9",
"101009": "4.1.0 Beta 10",
"101010": "4.1.0",
"101011": "4.1.1",
"101012": "4.1.2"
}
@@ -22,8 +22,18 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* Front Navigation Extension: Chat
*/
class _Chat
class _Chat extends \IPS\core\FrontNavigation\FrontNavigationAbstract
{
/**
* Get Type Title which will display in the AdminCP Menu Manager
*
* @return string
*/
public static function typeTitle()
{
return \IPS\Member::loggedIn()->language()->addToStack('frontnavigation_chat');
}
/**
* Can access?
*
@@ -31,7 +41,7 @@ class _Chat
*/
public function canView()
{
return !\IPS\Application::load('chat')->hide_tab and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'chat', 'chat' ) );
return parent::canView() and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'chat', 'chat' ) );
}
/**
@@ -63,14 +73,4 @@ class _Chat
{
return \IPS\Dispatcher::i()->application->directory === 'chat';
}
/**
* Children
*
* @return array
*/
public function children()
{
return array();
}
}
@@ -27,7 +27,7 @@ class _ChatAccess
/**
* Process Form
*
* @param \IPS\Form\Tabbed $form The form
* @param \IPS\Helpers\Form $form The form
* @param \IPS\Member\Group $group Existing Group
* @return void
*/
@@ -27,7 +27,7 @@ class _ChatBanned
/**
* Process Form
*
* @param \IPS\Form\Tabbed $form The form
* @param \IPS\Helpers\Form $form The form
* @param \IPS\Member $member Existing Member
* @return void
*/
+1 -1
View File
@@ -49,7 +49,7 @@ class chat_hook_tabCount extends _HOOK_CLASS_
\IPS\Output::i()->endBodyCode .= <<<HTML
<script type='text/javascript'>
$('.elNavigation_app_chat_Chat').append( $('<span/>').addClass('ipsNotificationCount').text('{$count}') );
$('[data-role="navBarItem"][data-navApp="chat"][data-navExt="Chat"]').append( $('<span/>').addClass('ipsNotificationCount').text('{$count}') );
</script>
HTML;
}
+4 -1
View File
@@ -11,7 +11,10 @@ class chat_hook_tabCountLoad extends _HOOK_CLASS_
public function __construct()
{
parent::__construct();
$this->initLoad[] = 'chatters';
if ( \IPS\CACHE_METHOD === 'None' )
{
$this->initLoad[] = 'chatters';
}
}
}
@@ -0,0 +1 @@
!function(){function t(t){this.message=t}var r="undefined"!=typeof exports?exports:this,e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";t.prototype=new Error,t.prototype.name="InvalidCharacterError",r.btoa||(r.btoa=function(r){for(var o,n,a=String(r),i=0,c=e,d="";a.charAt(0|i)||(c="=",i%1);d+=c.charAt(63&o>>8-i%1*8)){if(n=a.charCodeAt(i+=.75),n>255)throw new t("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");o=o<<8|n}return d}),r.atob||(r.atob=function(r){var o=String(r).replace(/=+$/,"");if(o.length%4==1)throw new t("'atob' failed: The string to be decoded is not correctly encoded.");for(var n,a,i=0,c=0,d="";a=o.charAt(c++);~a&&(n=i%4?64*n+a:a,i++%4)?d+=String.fromCharCode(255&n>>(-2*i&6)):0)a=e.indexOf(a);return d})}();
@@ -87,11 +87,12 @@ class _settings extends \IPS\Dispatcher\Controller
}
), NULL, NULL, NULL, 'ipschat_online' ) );
if ( $values = $form->values( TRUE ) )
if ( $values = $form->values() )
{
\IPS\Lang::saveCustom( 'chat', "ipschat_rules", $values['ipschat_rules_text'] );
unset( $values['ipschat_rules_text'] );
$values['ipchat_hide_usermessage'] = !$values['ipchat_hide_usermessage'];
$values['ipschat_online'] = implode( ',', $values['ipschat_online'] );
$form->saveAsSettings( $values );
/* Clear guest page caches */
@@ -175,6 +175,12 @@ class _action extends \IPS\Content\Controller
*/
protected function ping()
{
/* Still online? */
if ( $offlineMessage = \IPS\Application::load('chat')->offlineMessage() )
{
\IPS\Output::i()->json( array( 'message' => $offlineMessage ), 500 );
}
/* Make sure there is an ID */
if( !\IPS\Request::i()->id )
{
+28 -44
View File
@@ -74,48 +74,9 @@ class _view extends \IPS\Content\Controller
}
/* Figure out if chat is online due to time restrictions */
if( \IPS\Settings::i()->ipschat_online )
if ( $offlineMessage = \IPS\Application::load('chat')->offlineMessage() )
{
$times = explode( ',', \IPS\Settings::i()->ipschat_online );
if( count( $times ) AND $times[0] )
{
/* Do we need to adjust the time zone? */
if( isset( $times[2] ) AND $times[2] != \IPS\Member::loggedIn()->timezone )
{
$start = new \IPS\DateTime( '2015-01-01 ' . $times[0], new \DateTimeZone( $times[2] ) );
$start->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
$times[0] = $start->format( 'H:i' );
$end = new \IPS\DateTime( '2015-01-01 ' . $times[1], new \DateTimeZone( $times[2] ) );
$end->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
$times[1] = $end->format( 'H:i' );
}
$currentTime = new \IPS\DateTime( NULL, new \DateTimeZone( ( isset( $times[2] ) ) ? $times[2] : \IPS\Member::loggedIn()->timezone ) );
$currentTime->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
$currentTime = $currentTime->format( 'H:i' );
/* Convert times to floats, as that is simple to compare */
$start = str_replace( ':', '.', $times[0] );
$end = str_replace( ':', '.', $times[1] );
$currentTime = str_replace( ':', '.', $currentTime );
if( $end > $start )
{
if( !( $currentTime >= $start ) OR !( $currentTime < $end ) )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'chat_currently_offline', FALSE, array( 'sprintf' => $start ) ), '1H269/I', 403, 'chat_offline_admin' );
}
}
else
{
if( !( $currentTime >= $start ) AND $currentTime >= $end )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'chat_currently_offline', FALSE, array( 'sprintf' => $start ) ), '1H269/J', 403, 'chat_offline_admin' );
}
}
}
\IPS\Output::i()->error( $offlineMessage, '1H269/H', 403, 'chat_offline_admin' );
}
parent::execute();
@@ -130,7 +91,7 @@ class _view extends \IPS\Content\Controller
{
/* Initiate output */
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'jquery/jquery.rangyinputs.js', 'core', 'interface' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'buzz/buzz.min.js', 'chat', 'interface' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'buzz/buzz.min.js', 'core', 'interface' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'esrever/esrever.js', 'chat', 'interface' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_chat.js', 'chat', 'front' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'chat.css', 'chat', 'front' ) );
@@ -345,7 +306,7 @@ class _view extends \IPS\Content\Controller
$chatters[ $username ] = array(
'user_id' => $_thisRecord[0],
'username' => htmlspecialchars( $username, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'username' => htmlspecialchars( $this->uncleanUsername( $username ), ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ),
'formattedUsername' => \IPS\Member\Group::load( $member->member_group_id )->formatName( $member->name ),
'forumUserID' => $member->member_id,
'canBeIgnored' => $member->member_id ? !$member->group['gbw_cannot_be_ignored'] : 1,
@@ -403,7 +364,12 @@ class _view extends \IPS\Content\Controller
$emoticons = array();
foreach ( \IPS\Db::i()->select( '*', 'core_emoticons', NULL, 'emo_set,emo_position' ) as $row )
{
$emoticons[ $row['typed'] ] = (string) \IPS\File::get( 'core_Emoticons', $row['image'] )->url;
$emoticons[ $row['typed'] ] = array( 'image' => (string) \IPS\File::get( 'core_Emoticons', $row['image'] )->url, 'width' => $row['width'], 'height' => $row['height'] );
if( $row['image_2x'] )
{
$emoticons[ $row['typed'] ]['image_2x'] = (string) \IPS\File::get( 'core_Emoticons', $row['image_2x'] )->url . ' 2x';
}
}
/* We store the chat options in our session in case we choose to leave the room */
@@ -478,4 +444,22 @@ class _view extends \IPS\Content\Controller
return $username;
}
/**
* Unclean username for chat
*
* @param string Username
* @return string
*/
protected function uncleanUsername( $username )
{
$username = str_replace( "__PS__", "+", $username );
$username = str_replace( "__E__", "=", $username );
$username = str_replace( "__P__", "%", $username );
$username = str_replace( "__A__", "&", $username );
$username = str_replace( "__C__", ",", $username );
$username = str_replace( "__N__", "\n", $username );
return $username;
}
}
@@ -52,7 +52,7 @@ class _Upgrade
}
/* Add rules text */
\IPS\Lang::saveCustom( 'core', "ipschat_rules", html_entity_decode( \IPS\Settings::i()->ipschat_rules, ENT_QUOTES, 'UTF-8' ) );
\IPS\Lang::saveCustom( 'core', "ipschat_rules", \IPS\Text\Parser::utf8mb4SafeDecode( \IPS\Settings::i()->ipschat_rules ) );
/* Add online/offline start value */
\IPS\Db::i()->replace( 'core_sys_conf_settings', array(
+93 -30
View File
@@ -16,9 +16,10 @@ spl_autoload_register( function( $class )
if ( mb_substr( $class, 0, 15 ) === 'IPS\cms\Records' and is_numeric( mb_substr( $class, 15, 1 ) ) )
{
$databaseId = mb_substr( $class, 15 );
$titleField = \IPS\cms\Databases::load( $databaseId )->field_title;
$contentField = \IPS\cms\Databases::load( $databaseId )->field_content;
$titleLang = 'content_db_lang_sl_' . $databaseId;
$databases = \IPS\cms\Databases::databases();
$titleField = $databases[ $databaseId ]->field_title;
$contentField = $databases[ $databaseId ]->field_content;
$titleLang = 'content_db_lang_su_' . $databaseId;
$data = <<<EOF
namespace IPS\cms;
@@ -62,6 +63,7 @@ spl_autoload_register( function( $class )
'last_review_name' => 'record_last_review_name',
'updated' => 'record_last_comment'
);
public static \$pagePath;
}
EOF;
eval( $data );
@@ -75,6 +77,7 @@ EOF;
namespace IPS\cms\Records;
class Comment{$databaseId} extends Comment
{
protected static \$multitons = array();
public static \$customDatabaseId = $databaseId;
public static \$itemClass = 'IPS\cms\Records{$databaseId}';
public static \$title = 'content_record_comments_title_{$databaseId}';
@@ -91,6 +94,7 @@ EOF;
namespace IPS\cms\Records;
class Review{$databaseId} extends Review
{
protected static \$multitons = array();
public static \$customDatabaseId = $databaseId;
public static \$itemClass = 'IPS\cms\Records{$databaseId}';
public static \$title = 'content_record_reviews_title_{$databaseId}';
@@ -107,8 +111,10 @@ EOF;
namespace IPS\cms;
class Categories{$databaseId} extends Categories
{
protected static \$multitons = array();
public static \$customDatabaseId = $databaseId;
public static \$contentItemClass = 'IPS\cms\Records{$databaseId}';
protected static \$containerIds = NULL;
}
EOF;
@@ -123,6 +129,7 @@ EOF;
namespace IPS\cms\Records;
class RecordsTopicSync{$databaseId} extends \IPS\cms\Records{$databaseId}
{
protected static \$multitons = array();
public static \$customDatabaseId = $databaseId;
public static \$databaseTable = 'cms_custom_database_{$databaseId}';
public static \$databaseColumnId = 'record_topicid';
@@ -145,6 +152,7 @@ EOF;
namespace IPS\cms\Records;
class CommentTopicSync{$databaseId} extends CommentTopicSync
{
protected static \$multitons = array();
public static \$customDatabaseId = $databaseId;
public static \$itemClass = 'IPS\cms\Records\RecordsTopicSync{$databaseId}';
public static \$title = 'content_record_comments_title_{$databaseId}';
@@ -233,8 +241,8 @@ class _Application extends \IPS\Application
* @return array
*/
public function extensions( $app, $extension, $construct=TRUE, $checkAccess=FALSE )
{
$classes = parent::extensions( $app, $extension, $construct );
{
$classes = parent::extensions( $app, $extension, $construct, $checkAccess );
if ( $extension === 'EditorLocations' )
{
@@ -254,35 +262,12 @@ class _Application extends \IPS\Application
{
try
{
$classes[ 'Records' . $obj->_id ] = new $classname;
$classes[ 'Records' . $obj->_id ] = new $classname( $checkAccess === TRUE ? \IPS\Member::loggedIn() : ( $checkAccess === FALSE ? NULL : $checkAccess ) );
}
catch( \RuntimeException $e ){}
}
}
}
else if ( $checkAccess and $extension === 'ContentRouter' )
{
if ( isset( $classes['Records'] ) )
{
foreach ( $classes['Records']->classes as $id => $name )
{
if ( ! $name::database()->can( 'view' ) )
{
unset( $classes['Records']->classes[ $id ] );
continue;
}
if ( isset( $name::$reviewClass ) and ! $name::database()->options['reviews'] )
{
$_class = $classes['Records']->classes[ $id ];
if ( class_exists( $_class ) )
{
$_class::$reviewClass = NULL;
}
}
}
}
}
return $classes;
}
@@ -375,12 +360,48 @@ class _Application extends \IPS\Application
$database->search = 1;
$database->comment_bump = 1; # Just new comments bump record
$database->rss = 1;
$database->fixed_field_perms = array( 'record' => array( 'visible' => true, 'perm_view' => '*', 'perm_2' => '*', 'perm_3' => '*' ) );
$database->options['comments'] = 1;
$database->field_sort = 'primary_id_field';
$database->field_direction = 'asc';
$database->field_perpage = 25;
$database->save();
/* Create default record */
$item = 'IPS\cms\Records' . $database->id;
$comment = 'IPS\cms\Records\Comment' . $database->id;
$container = 'IPS\cms\Categories' . $database->id;
$link = (string) \IPS\Http\Url::ips('pages_docs');
$content = <<<EOF
<p>Welcome to Pages!</p>
<p>Pages extends your site with custom content management designed especially for communities.
Create brand new sections of your community using features like blocks, databases and articles,
pulling in data from other areas of your community.</p>
<p>Create custom pages in your community using our drag'n'drop, WYSIWYG editor.
Build blocks that pull in all kinds of data from throughout your community to create dynamic pages,
or use one of the ready-made widgets we include with the IPS Community Suite.</p>
<p><br></p>
<p><a href="{$link}">View our Pages documentation</a></p>
EOF;
$titleField = 'field_' . $database->field_title;
$contentField = 'field_' . $database->field_content;
$category = $container::load( $database->_default_category );
$member = \IPS\Member::loggedIn()->member_id ? \IPS\Member::loggedIn() : \IPS\Member::load(1);
$record = $item::createItem( $member, \IPS\Request::i()->ipAddress(), \IPS\DateTime::ts( time() ), $category, FALSE );
$record->$titleField = "Welcome to Pages";
$record->$contentField = $content;
$record->save();
\IPS\Content\Search\Index::i()->index( $record );
$category->last_record_date = time();
$category->save();
/* Create the page */
$pageValues = array(
'page_name' => "Articles",
@@ -389,13 +410,55 @@ class _Application extends \IPS\Application
'page_folder_id' => 0,
'page_ipb_wrapper' => 1,
'page_show_sidebar' => 1,
'page_content' => '{database="' . $database->id . '"}',
'page_type' => 'builder',
'page_template' => 'page_builder__single_column__page_page_builder_single_column'
);
$page = \IPS\cms\Pages\Page::createFromForm( $pageValues, 'html' );
$page->setAsDefault();
$database->page_id = $page->id;
$database->save();
unset( \IPS\Data\Store::i()->pages_page_urls );
$defaultWidgets = array();
$buttonUrl = (string) \IPS\Http\Url::internal( 'applications/cms/interface/default/block_arrow.png', 'none' );
$defaultContent = <<<EOF
<p>
<strong>Welcome to Pages!</strong>
</p>
<p>
To get started, make sure you are logged in and click the arrow on the left hand side <img src="{$buttonUrl}"> to expand the block manager.
<br>
You can move, add and edit blocks without the need for complex coding!
</p>
EOF;
/* Default WYSIWYG widget */
$defaultWidgets[] = array(
'app' => 'cms',
'key' => 'Wysiwyg',
'unique' => uniqid(),
'configuration' => array( 'content' => $defaultContent )
);
/* Default database widget */
$defaultWidgets[] = array(
'app' => 'cms',
'key' => 'Database',
'unique' => uniqid(),
'configuration' => array( 'database' => $database->id )
);
\IPS\Db::i()->insert( 'cms_page_widget_areas', array(
'area_page_id' => $page->id,
'area_widgets' => json_encode( $defaultWidgets ),
'area_area' => 'col1',
'area_orientation' => 'horizontal'
) );
/* Add block container (custom)*/
$container = new \IPS\cms\Blocks\Container;
$container->parent_id = 0;
+3 -3
View File
@@ -18,11 +18,11 @@
"do": "",
"restriction": "template_manage"
},
"menu": {
"media": {
"tab": "cms",
"controller": "menu",
"controller": "media",
"do": "",
"restriction": null
"restriction": "media_manage"
}
},
"databases": {
+5 -5
View File
@@ -18,11 +18,11 @@
"template_add_edit": "template_add_edit",
"template_delete": "template_delete"
},
"menu": {
"manage": "menu_manage",
"add": "menu_add",
"edit": "menu_edit",
"delete": "menu_delete"
"media": {
"media_manage": "media_manage",
"media_add": "media_add",
"media_edit": "media_edit",
"media_delete": "media_delete"
}
},
"databases": {
+453 -79
View File
@@ -1,32 +1,370 @@
<?xml version="1.0" encoding="UTF-8"?>
<theme name="Default" author_name="Invision Power Services, Inc" author_url="http://www.invisionpower.com">
<template template_key="database_category_articles_entry" template_title="entry" template_desc="" template_location="database" template_group="category_articles" template_params="$record, $database" template_app="" template_type="template"><![CDATA[<article class='cCmsCategoryFeaturedEntry {{if $record->hidden()}}ipsModerated{{endif}}'>
<template template_key="database_category_2_column_first_featured_entry" template_title="entry" template_desc="" template_location="database" template_group="category_2_column_first_featured" template_params="$record, $database, $id" template_app="" template_type="template"><![CDATA[{{$size = ( $id ) ? 'tiny' : 'small';}}
<div class='{{if $id}}ipsGrid_span6{{else}}ipsGrid_span12{{endif}}'>
<article class='cCmsCategoryFeaturedEntry {{if $record->hidden()}}ipsModerated{{endif}}'>
<header class='ipsPhotoPanel ipsPhotoPanel_notPhone ipsPhotoPanel_{$size} ipsSpacer_bottom'>
{template="userPhoto" app="core" params="$record->author(), $size" group="global"}
<div>
<h2 class='ipsType_pageTitle'>
{{if $record->prefix()}}
{template="prefix" group="global" app="core" params="$record->prefix( TRUE ), $record->prefix()"}
{{endif}}
<a href="{$record->url()}" title="{lang="read_more_about" sprintf="$record->_title"}">
{{if $record->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="cms_unread_record"}"><i class="fa fa-circle"></i></span>
{{endif}}
{wordbreak="$record->_title"}
</a>
{{if $record->mapped('pinned') || $record->mapped('featured') || $record->hidden() === -1 || $record->hidden() === 1}}
{{if $record->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$record->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $record->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $record->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $record->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
</h2>
<p class='ipsType_light ipsType_reset cmsInformation'>
{lang="cms_byline" htmlsprintf="$record->author()->link(), $record->container()->url(), $record->container()->_title"}{datetime="$record->record_publish_date"}
</p>
</div>
</header>
{{if count( $record->customFieldsForDisplay('listing') )}}
<div class='ipsDataItem_meta'>
{{foreach $record->customFieldsForDisplay('listing') as $fieldId => $fieldValue}}
{{if $fieldValue}}
{$fieldValue|raw}
{{endif}}
{{endforeach}}
</div>
{{endif}}
<section class='ipsType_normal ipsType_richText ipsType_break ipsSpacer_both' data-ipsTruncate data-ipsTruncate-size='7 lines' data-ipsTruncate-type='remove'>
{{if $record->record_image}}
<div class="cCmsRecord_image">
<img class="ipsImage" src="{file="$record->record_image" extension="cms_Records"}">
</div>
{{endif}}
{$record->truncated()|raw}
</section>
{{if count( $record->tags() )}}
{template="tags" group="global" app="core" params="$record->tags()"}
{{endif}}
<ul class='ipsList_inline'>
<li><strong><a href='{$record->url()}' title="{lang="read_more_about" sprintf="$record->name"}">{lang="read_more"}</a></strong></li>
{{if $record::database()->options['reviews']}}
<li>{template="rating" app="core" params="'small', $record->averageReviewRating(), \IPS\Settings::i()->reviews_rating_out_of" group="global"}</li>
{{endif}}
<li><a href='{$record->url()}#comments' title='{lang="view_comments"}'><i class='fa fa-comment'></i> {lang="num_comments" pluralize="$record->record_comments"}</a></li>
<li class='ipsType_light'>{lang="num_views_with_number" pluralize="$record->record_views"}</li>
</ul>
</article>
</div>]]></template>
<template template_key="database_category_2_column_first_featured_index" template_title="index" template_desc="" template_location="database" template_group="category_2_column_first_featured" template_params="$database, $articles, $url, $pagination" template_app="" template_type="template"><![CDATA[<div class='ipsPageHeader ipsClearfix ipsSpacer_bottom'>
{{if $database->use_categories}}
<div class='ipsPos_right ipsResponsive_noFloat'>
<a href="{$url->setQueryString('show', 'categories')}" class="ipsButton ipsButton_medium ipsButton_fullWidth ipsButton_link"><i class="fa fa-folder-open"></i> {lang="cms_show_categories"}</a>
</div>
{{endif}}
<h1 class='ipsType_pageTitle'>{$database->_title}</h1>
{{if $database->_description}}
<div class='ipsPageHeader_info ipsType_light'>
{$database->_description}
</div>
{{endif}}
</div>
{{if $database->can('add') or \IPS\Member::loggedIn()->member_id}}
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both ipsResponsive_hidePhone">
{{if $database->can('add')}}
<li class='ipsToolList_primaryAction'>
<a class="ipsButton ipsButton_medium ipsButton_important ipsButton_fullWidth" {{if $database->use_categories}}data-ipsDialog="1" data-ipsDialog-size="narrow" data-ipsDialog-title="{lang="cms_select_category"}"{{endif}} href="{$url->setQueryString( array( 'do' => 'form', 'd' => \IPS\cms\Databases\Dispatcher::i()->databaseId ) )}">{lang="cms_add_new_record_button" sprintf="$database->recordWord( 1 )"}</a>
</li>
{{endif}}
</ul>
{{endif}}
<hr class='ipsHr'>
<section class='ipsType_normal ipsSpacer_both'>
{{if count($articles)}}
{{foreach $articles as $id => $record}}
{{if $id == 0}}
<div class='ipsGrid ipsGrid_collapsePhone'>
{template="entry" app="cms" location="database" group="category_2_column_first_featured" params="$record, $database, 0"}
</div>
{{else}}
{{if $id % 2}}
<div class='ipsGrid ipsGrid_collapsePhone cmsCategory2col'>
{{endif}}
{template="entry" app="cms" location="database" group="category_2_column_first_featured" params="$record, $database, $id"}
{{if $id % 2 == 0}}
</div>
{{endif}}
{{endif}}
{{endforeach}}
{{endif}}
</section>
{{if $database->featured_settings['pagination'] and ( $pagination['pages'] > 1 )}}
{template="pagination" app="core" location="global" group="global" params="$url, $pagination['pages'], $pagination['page'], $database->featured_settings['perpage'], TRUE, 'page'"}
{{endif}}]]></template>
<template template_key="database_category_2_column_image_feature_entry" template_title="entry" template_desc="" template_location="database" template_group="category_2_column_image_feature" template_params="$record, $database, $id" template_app="" template_type="template"><![CDATA[<div class='ipsGrid_span6'>
<article class='cCmsCategoryFeaturedEntry {{if $record->hidden()}}ipsModerated{{endif}} cms2ColImageFeature'>
{{if $record->record_image}}
<div class="cCmsRecord_image">
<a href="{$record->url()}" title="{lang="read_more_about" sprintf="$record->_title"}"><img class="ipsImage" src="{file="$record->record_image" extension="cms_Records"}"></a>
</div>
{{endif}}
{{if $record->prefix()}}
{template="prefix" group="global" app="core" params="$record->prefix( TRUE ), $record->prefix()"}
{{endif}}
<h2 class='ipsType_pageTitle'><a href="{$record->url()}" title="{lang="read_more_about" sprintf="$record->_title"}">
{wordbreak="$record->_title"}
</a></h2>
</article>
</div>]]></template>
<template template_key="database_category_2_column_image_feature_index" template_title="index" template_desc="" template_location="database" template_group="category_2_column_image_feature" template_params="$database, $articles, $url, $pagination" template_app="" template_type="template"><![CDATA[<div class='ipsPageHeader ipsClearfix ipsSpacer_bottom'>
{{if $database->use_categories}}
<div class='ipsPos_right ipsResponsive_noFloat'>
<a href="{$url->setQueryString('show', 'categories')}" class="ipsButton ipsButton_medium ipsButton_fullWidth ipsButton_link"><i class="fa fa-folder-open"></i> {lang="cms_show_categories"}</a>
</div>
{{endif}}
<h1 class='ipsType_pageTitle'>{$database->_title}</h1>
{{if $database->_description}}
<div class='ipsPageHeader_info ipsType_light'>
{$database->_description}
</div>
{{endif}}
</div>
{{if $database->can('add') or \IPS\Member::loggedIn()->member_id}}
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both ipsResponsive_hidePhone">
{{if $database->can('add')}}
<li class='ipsToolList_primaryAction'>
<a class="ipsButton ipsButton_medium ipsButton_important ipsButton_fullWidth" {{if $database->use_categories}}data-ipsDialog="1" data-ipsDialog-size="narrow" data-ipsDialog-title="{lang="cms_select_category"}"{{endif}} href="{$url->setQueryString( array( 'do' => 'form', 'd' => \IPS\cms\Databases\Dispatcher::i()->databaseId ) )}">{lang="cms_add_new_record_button" sprintf="$database->recordWord( 1 )"}</a>
</li>
{{endif}}
</ul>
{{endif}}
<hr class='ipsHr'>
<section class='ipsType_normal ipsSpacer_both'>
{{if count($articles)}}
{{foreach $articles as $id => $record}}
{{if $id % 2 == 0}}
<div class='ipsGrid ipsGrid_collapsePhone'>
{{endif}}
{template="entry" app="cms" location="database" group="category_2_column_image_feature" params="$record, $database, $id"}
{{if $id % 2 == 1}}
</div>
{{endif}}
{{endforeach}}
{{endif}}
</section>
{{if $database->featured_settings['pagination'] and ( $pagination['pages'] > 1 )}}
{template="pagination" app="core" location="global" group="global" params="$url, $pagination['pages'], $pagination['page'], $database->featured_settings['perpage'], TRUE, 'page'"}
{{endif}}]]></template>
<template template_key="database_category_3_column_first_featured_entry" template_title="entry" template_desc="" template_location="database" template_group="category_3_column_first_featured" template_params="$record, $database, $id" template_app="" template_type="template"><![CDATA[<div class='{{if $id}}ipsGrid_span4{{else}}ipsGrid_span12{{endif}}'>
<article class='cCmsCategoryFeaturedEntry {{if $record->hidden()}}ipsModerated{{endif}}'>
<header class='{{if $id === 0}}ipsPhotoPanel ipsPhotoPanel_notPhone ipsPhotoPanel_small{{endif}} ipsSpacer_bottom'>
{{if $id === 0}}{template="userPhoto" app="core" params="$record->author(), 'small'" group="global"}{{endif}}
<div>
<h2 class='ipsType_pageTitle'>
{{if $record->prefix()}}
{template="prefix" group="global" app="core" params="$record->prefix( TRUE ), $record->prefix()"}
{{endif}}
<a href="{$record->url()}" title="{lang="read_more_about" sprintf="$record->_title"}">
{{if $record->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="cms_unread_record"}"><i class="fa fa-circle"></i></span>
{{endif}}
{wordbreak="$record->_title"}
</a>
{{if $record->mapped('pinned') || $record->mapped('featured') || $record->hidden() === -1 || $record->hidden() === 1}}
{{if $record->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$record->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $record->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $record->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $record->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
</h2>
<p class='ipsType_light ipsType_reset cmsInformation'>
{lang="cms_byline" htmlsprintf="$record->author()->link(), $record->container()->url(), $record->container()->_title"}{datetime="$record->record_publish_date"}
</p>
</div>
</header>
{{if count( $record->customFieldsForDisplay('listing') )}}
<div class='ipsDataItem_meta'>
{{foreach $record->customFieldsForDisplay('listing') as $fieldId => $fieldValue}}
{{if $fieldValue}}
{$fieldValue|raw}
{{endif}}
{{endforeach}}
</div>
{{endif}}
<section class='ipsType_normal ipsType_richText ipsType_break ipsSpacer_both' data-ipsTruncate data-ipsTruncate-size='7 lines' data-ipsTruncate-type='remove'>
{{if $record->record_image}}
<div class="cCmsRecord_image">
<img class="ipsImage" src="{file="$record->record_image" extension="cms_Records"}">
</div>
{{endif}}
{$record->truncated()|raw}
</section>
{{if count( $record->tags() )}}
{template="tags" group="global" app="core" params="$record->tags()"}
{{endif}}
<ul class='ipsList_inline'>
<li><strong><a href='{$record->url()}' title="{lang="read_more_about" sprintf="$record->name"}">{lang="read_more"}</a></strong></li>
{{if $record::database()->options['reviews']}}
<li>{template="rating" app="core" params="'small', $record->averageReviewRating(), \IPS\Settings::i()->reviews_rating_out_of" group="global"}</li>
{{endif}}
<li><a href='{$record->url()}#comments' title='{lang="view_comments"}'><i class='fa fa-comment'></i> {lang="num_comments" pluralize="$record->record_comments"}</a></li>
<li class='ipsType_light'>{lang="num_views_with_number" pluralize="$record->record_views"}</li>
</ul>
</article>
</div>]]></template>
<template template_key="database_category_3_column_first_featured_index" template_title="index" template_desc="" template_location="database" template_group="category_3_column_first_featured" template_params="$database, $articles, $url, $pagination" template_app="" template_type="template"><![CDATA[<div class='ipsPageHeader ipsClearfix ipsSpacer_bottom'>
{{if $database->use_categories}}
<div class='ipsPos_right ipsResponsive_noFloat'>
<a href="{$url->setQueryString('show', 'categories')}" class="ipsButton ipsButton_medium ipsButton_fullWidth ipsButton_link"><i class="fa fa-folder-open"></i> {lang="cms_show_categories"}</a>
</div>
{{endif}}
<h1 class='ipsType_pageTitle'>{$database->_title}</h1>
{{if $database->_description}}
<div class='ipsPageHeader_info ipsType_light'>
{$database->_description}
</div>
{{endif}}
</div>
{{if $database->can('add') or \IPS\Member::loggedIn()->member_id}}
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both ipsResponsive_hidePhone">
{{if $database->can('add')}}
<li class='ipsToolList_primaryAction'>
<a class="ipsButton ipsButton_medium ipsButton_important ipsButton_fullWidth" {{if $database->use_categories}}data-ipsDialog="1" data-ipsDialog-size="narrow" data-ipsDialog-title="{lang="cms_select_category"}"{{endif}} href="{$url->setQueryString( array( 'do' => 'form', 'd' => \IPS\cms\Databases\Dispatcher::i()->databaseId ) )}">{lang="cms_add_new_record_button" sprintf="$database->recordWord( 1 )"}</a>
</li>
{{endif}}
</ul>
{{endif}}
<hr class='ipsHr'>
<section class='ipsType_normal ipsSpacer_both'>
{{if count($articles)}}
{{foreach $articles as $id => $record}}
{{if $id == 0}}
<div class='ipsGrid ipsGrid_collapsePhone'>
{template="entry" app="cms" location="database" group="category_3_column_first_featured" params="$record, $database, 0"}
</div>
{{else}}
{{if ($id - 1) % 3 == 0}}
<div class='ipsGrid ipsGrid_collapsePhone cmsCategory3col'>
{{endif}}
{template="entry" app="cms" location="database" group="category_3_column_first_featured" params="$record, $database, $id"}
{{if ($id - 1) % 3 == 2}}
</div>
{{endif}}
{{endif}}
{{endforeach}}
{{endif}}
</section>
{{if $database->featured_settings['pagination'] and ( $pagination['pages'] > 1 )}}
{template="pagination" app="core" location="global" group="global" params="$url, $pagination['pages'], $pagination['page'], $database->featured_settings['perpage'], TRUE, 'page'"}
{{endif}}]]></template>
<template template_key="database_category_3_column_image_feature_entry" template_title="entry" template_desc="" template_location="database" template_group="category_3_column_image_feature" template_params="$record, $database, $id" template_app="" template_type="template"><![CDATA[<div class='ipsGrid_span4'>
<article class='cCmsCategoryFeaturedEntry {{if $record->hidden()}}ipsModerated{{endif}} cms3ColImageFeature'>
{{if $record->record_image}}
<div class="cCmsRecord_image">
<a href="{$record->url()}" title="{lang="read_more_about" sprintf="$record->_title"}"><img class="ipsImage" src="{file="$record->record_image" extension="cms_Records"}"></a>
</div>
{{endif}}
{{if $record->prefix()}}
{template="prefix" group="global" app="core" params="$record->prefix( TRUE ), $record->prefix()"}
{{endif}}
<h2 class='ipsType_pageTitle'><a href="{$record->url()}" title="{lang="read_more_about" sprintf="$record->_title"}">
{wordbreak="$record->_title"}
</a></h2>
</article>
</div>]]></template>
<template template_key="database_category_3_column_image_feature_index" template_title="index" template_desc="" template_location="database" template_group="category_3_column_image_feature" template_params="$database, $articles, $url, $pagination" template_app="" template_type="template"><![CDATA[<div class='ipsPageHeader ipsClearfix ipsSpacer_bottom'>
{{if $database->use_categories}}
<div class='ipsPos_right ipsResponsive_noFloat'>
<a href="{$url->setQueryString('show', 'categories')}" class="ipsButton ipsButton_medium ipsButton_fullWidth ipsButton_link"><i class="fa fa-folder-open"></i> {lang="cms_show_categories"}</a>
</div>
{{endif}}
<h1 class='ipsType_pageTitle'>{$database->_title}</h1>
{{if $database->_description}}
<div class='ipsPageHeader_info ipsType_light'>
{$database->_description}
</div>
{{endif}}
</div>
{{if $database->can('add') or \IPS\Member::loggedIn()->member_id}}
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both ipsResponsive_hidePhone">
{{if $database->can('add')}}
<li class='ipsToolList_primaryAction'>
<a class="ipsButton ipsButton_medium ipsButton_important ipsButton_fullWidth" {{if $database->use_categories}}data-ipsDialog="1" data-ipsDialog-size="narrow" data-ipsDialog-title="{lang="cms_select_category"}"{{endif}} href="{$url->setQueryString( array( 'do' => 'form', 'd' => \IPS\cms\Databases\Dispatcher::i()->databaseId ) )}">{lang="cms_add_new_record_button" sprintf="$database->recordWord( 1 )"}</a>
</li>
{{endif}}
</ul>
{{endif}}
<hr class='ipsHr'>
<section class='ipsType_normal ipsSpacer_both'>
{{if count($articles)}}
{{foreach $articles as $id => $record}}
{{if $id % 3 == 0}}
<div class='ipsGrid ipsGrid_collapsePhone'>
{{endif}}
{template="entry" app="cms" location="database" group="category_3_column_image_feature" params="$record, $database, $id"}
{{if $id % 3 == 2}}
</div>
{{endif}}
{{endforeach}}
{{endif}}
</section>
{{if $database->featured_settings['pagination'] and ( $pagination['pages'] > 1 )}}
{template="pagination" app="core" location="global" group="global" params="$url, $pagination['pages'], $pagination['page'], $database->featured_settings['perpage'], TRUE, 'page'"}
{{endif}}]]></template>
<template template_key="database_category_articles_entry" template_title="entry" template_desc="" template_location="database" template_group="category_articles" template_params="$record, $database" template_app="" template_type="template"><![CDATA[<article class='cCmsCategoryFeaturedEntry ipsClear ipsClearfix {{if $record->hidden()}}ipsModerated{{endif}}'>
<header class='ipsPhotoPanel ipsPhotoPanel_notPhone ipsPhotoPanel_small ipsSpacer_bottom'>
{template="userPhoto" app="core" params="$record->author()" group="global"}
<div>
<h2 class='ipsType_pageTitle'>
{{if $record->prefix()}}
{template="prefix" group="global" app="core" params="$record->prefix( TRUE ), $record->prefix()"}
{template="prefix" group="global" app="core" params="$record->prefix( TRUE ), $record->prefix()"}
{{endif}}
{{if $record->mapped('pinned') || $record->mapped('featured') || $record->hidden() === -1 || $record->hidden() === 1}}
{{if $record->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$record->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $record->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $record->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $record->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
<a href="{$record->url()}" title="{lang="read_more_about" sprintf="$record->_title"}">
{{if $record->unread()}}
<span class='ipsItemStatus' data-ipsTooltip title="{lang="cms_unread_record"}"><i class="fa fa-circle"></i></span>
{{endif}}
{wordbreak="$record->_title"}
</a>
{{if $record->mapped('pinned') || $record->mapped('featured') || $record->hidden() === -1 || $record->hidden() === 1}}
{{if $record->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$record->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $record->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $record->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $record->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
</h2>
<p class='ipsType_light ipsType_reset'>
{lang="cms_byline" htmlsprintf="$record->author()->link(), $record->container()->url(), $record->container()->_title"}{datetime="$record->record_publish_date"}
@@ -42,26 +380,37 @@
{{endforeach}}
</div>
{{endif}}
<section class='ipsType_normal ipsType_richText ipsType_break ipsSpacer_both' data-ipsTruncate data-ipsTruncate-size='7 lines' data-ipsTruncate-type='remove'>
<div {{if $record->record_image}}class='ipsColumns ipsColumns_collapsePhone'{{endif}}>
{{if $record->record_image}}
<div class="cCmsRecord_image">
<img class="ipsImage" src="{file="$record->record_image" extension="cms_Records"}">
</div>
<div class='ipsColumn ipsColumn_medium'>
<div class="cCmsRecord_image">
<img class="ipsImage" src="{file="$record->_record_image_thumb" extension="cms_Records"}">
</div>
</div>
<div class='ipsColumn ipsColumn_fluid'>
{{endif}}
{$record->truncated()|raw}
</section>
{{if count( $record->tags() )}}
{template="tags" group="global" app="core" params="$record->tags()"}
{{endif}}
<ul class='ipsList_inline'>
<li><strong><a href='{$record->url()}' title="{lang="read_more_about" sprintf="$record->name"}">{lang="read_more"}</a></strong></li>
{{if $record::database()->options['reviews']}}
<li>{template="rating" app="core" params="'small', $record->averageReviewRating(), \IPS\Settings::i()->reviews_rating_out_of" group="global"}</li>
<section class='ipsType_normal ipsType_richText ipsType_break ipsSpacer_bottom' data-ipsTruncate data-ipsTruncate-size='7 lines' data-ipsTruncate-type='remove'>
{$record->truncated()|raw}
</section>
{{if count( $record->tags() )}}
{template="tags" group="global" app="core" params="$record->tags()"}
{{endif}}
<ul class='ipsList_inline ipsClear'>
<li><strong><a href='{$record->url()}' title="{lang="read_more_about" sprintf="$record->name"}">{lang="read_more"}</a></strong></li>
{{if $record::database()->options['reviews']}}
<li>{template="rating" app="core" params="'small', $record->averageReviewRating(), \IPS\Settings::i()->reviews_rating_out_of" group="global"}</li>
{{endif}}
<li><a href='{$record->url()}#comments' title='{lang="view_comments"}'><i class='fa fa-comment'></i> {lang="num_comments" pluralize="$record->record_comments"}</a></li>
<li class='ipsType_light'>{lang="num_views_with_number" pluralize="$record->record_views"}</li>
</ul>
{{if $record->record_image}}
</div>
{{endif}}
<li><a href='{$record->url()}#comments' title='{lang="view_comments"}'><i class='fa fa-comment'></i> {lang="num_comments" pluralize="$record->record_comments"}</a></li>
<li class='ipsType_light'>{lang="num_views_with_number" pluralize="$record->record_views"}</li>
</ul>
</div>
</article>]]></template>
<template template_key="database_category_articles_index" template_title="index" template_desc="" template_location="database" template_group="category_articles" template_params="$database, $articles, $url, $pagination" template_app="" template_type="template"><![CDATA[<div class='ipsPageHeader ipsClearfix ipsSpacer_bottom'>
{{if $database->use_categories}}
@@ -137,7 +486,7 @@
{{if $lastPost}}
<li>{template="userPhoto" app="core" group="global" params="$lastPost['author'], 'tiny'"}</li>
<li><a href="{$lastPost['record_url']}" class='ipsType_break ipsContained' title='{$lastPost['record_title']}'>{truncate="$lastPost['record_title']" length="30"}</a></li>
<li>{lang="byline_nodate" htmlsprintf="$lastPost['author']->link()"}</li>
<li class='ipsType_blendLinks'>{lang="byline_nodate" htmlsprintf="$lastPost['author']->link()"}</li>
<li data-short="1 dy" class="ipsType_light"><a href='{$lastPost['record_url']->setQueryString( 'do', 'getLastComment' )}' title='{lang="get_last_post"}' class='ipsType_blendLinks'>{datetime="$lastPost['date']"}</a></li>
{{else}}
<li class='ipsType_light ipsResponsive_showDesktop'>{lang="content_categories_index_no_records" sprintf="\IPS\cms\Databases::load( $category->database_id )->recordWord()"}</li>
@@ -190,14 +539,20 @@
</html>]]></template>
<template template_key="database_display_comment" template_title="comment" template_desc="" template_location="database" template_group="display" template_params="$item, $comment, $editorName, $app, $type, $class=''" template_app="" template_type="template"><![CDATA[{{$itemIdField = $item::$databaseColumnId; $idField = $comment::$databaseColumnId;}}
<div id='comment-{$comment->$idField}_wrap' data-controller='core.front.core.comment' data-commentApp='{$app}' data-commentType='{$type}' data-commentID="{$comment->$idField}" data-quoteData='{expression="json_encode( array('userid' => $comment->author()->member_id, 'username' => $comment->author()->name, 'timestamp' => $comment->mapped('date'), 'contentapp' => $app, 'contenttype' => $type, 'contentclass' => $class, 'contentid' => $item->$itemIdField, 'contentcommentid' => $comment->$idField) )"}' class='cPost_content ipsComment_content ipsType_medium {{if $comment->hidden()}}ipsModerated{{endif}} ipsFaded_withHover'>
{{if in_array( 'IPS\Content\Reputation', class_implements( $comment ) ) and settings.reputation_highlight and $comment->reputation() >= settings.reputation_highlight}}
<strong class='ipsComment_popularFlag' data-ipsTooltip title='{lang="this_is_a_popular_comment"}'><i class='fa fa-heart'></i></strong>
{{endif}}
<div class='ipsComment_header ipsPhotoPanel ipsPhotoPanel_mini ipsPhotoPanel_notPhone'>
{template="userPhoto" app="core" group="global" params="$comment->author(), 'mini', $comment->warningRef()"}
<div>
<p class='ipsPos_right ipsType_reset ipsType_blendLinks'>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->id ) )}' data-ipsTooltip title='{lang="share_this_comment"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elShareComment_{$comment->id}'><i class='fa fa-share-alt'></i></a>
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->id ) )}' data-ipsTooltip title='{lang="share_this_comment"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elShareComment_{$comment->id}' data-role='shareComment'><i class='fa fa-share-alt'></i></a>
{{if count( $item->commentMultimodActions() )}}
<input type="checkbox" name="multimod[{$comment->$idField}]" value="1" data-role="moderation" data-actions="{{if $comment->canSplit()}}split merge{{endif}} {{if $comment->hidden() === -1 AND $comment->canUnhide()}}unhide{{elseif $comment->hidden() === 1 AND $comment->canUnhide()}}approve{{elseif $comment->canHide()}}hide{{endif}} {{if $comment->canDelete()}}delete{{endif}}" data-state='{{if $comment->tableStates()}}{$comment->tableStates()}{{endif}}'>
<span class='ipsCustomInput'>
<input type="checkbox" name="multimod[{$comment->$idField}]" value="1" data-role="moderation" data-actions="{{if $comment->canSplit()}}split merge{{endif}} {{if $comment->hidden() === -1 AND $comment->canUnhide()}}unhide{{elseif $comment->hidden() === 1 AND $comment->canUnhide()}}approve{{elseif $comment->canHide()}}hide{{endif}} {{if $comment->canDelete()}}delete{{endif}}" data-state='{{if $comment->tableStates()}}{$comment->tableStates()}{{endif}}'>
<span></span>
</span>
{{endif}}
</p>
<h3 class='ipsComment_author ipsType_blendLinks'>
@@ -205,7 +560,7 @@
{template="reputationBadge" group="global" app="core" params="$comment->author()"}
</h3>
<p class='ipsComment_meta ipsType_light ipsType_medium'>
{$comment->dateLine()|raw}
<a href='{$comment->item()->url()->setQueryString( array( 'do' => 'findComment', 'comment' => $comment->id ) )}' class='ipsType_blendLinks' title='{lang="share_this_comment"}'>{$comment->dateLine()|raw}</a>
{{if $comment->editLine()}}
({lang="edited_lc"})
{{endif}}
@@ -222,11 +577,7 @@
{{endif}}
</div>
</div>
<div class='ipsAreaBackground_reset ipsPad'>
{{if in_array( 'IPS\Content\Reputation', class_implements( $comment ) ) and settings.reputation_highlight and $comment->reputation() >= settings.reputation_highlight}}
<strong class='ipsComment_popularFlag' data-ipsTooltip title='{lang="this_is_a_popular_comment"}'><i class='fa fa-star'></i></strong>
{{endif}}
<div class='ipsAreaBackground_reset ipsPad'>
<div data-role='commentContent' class='ipsType_normal ipsType_richText ipsType_break ipsContained' data-controller='core.front.core.lightboxedImages'>
{{if $comment->hidden() === 1 && $comment->author()->member_id == \IPS\Member::loggedIn()->member_id}}
<strong class='ipsType_medium ipsType_warning'><i class='fa fa-info-circle'></i> {lang="comment_awaiting_approval"}</strong>
@@ -340,7 +691,7 @@
<article itemscope itemtype="http://schema.org/Comment" id='elComment_{$comment->$idField}' class='ipsComment {{if $otherClasses}}{$otherClasses}{{endif}} {{if in_array( 'IPS\Content\Reputation', class_implements( $comment ) ) and settings.reputation_highlight and $comment->reputation() >= settings.reputation_highlight}}ipsComment_popular{{endif}} ipsComment_parent ipsClearfix ipsClear {{if $comment->isIgnored()}}ipsHide{{endif}} {{if $comment->hidden()}}ipsModerated{{endif}}'>
{template="comment" group="display" location="database" app="cms" params="$item, $comment, $item::$formLangPrefix . 'comment', $item::$application, $item::$module, $itemClassSafe"}
</article>]]></template>
<template template_key="database_display_comments" template_title="comments" template_desc="" template_location="database" template_group="display" template_params="$record" template_app="" template_type="template"><![CDATA[<div data-controller='core.front.core.commentFeed' data-commentsType='comments' data-baseURL='{$record->url()}' {{if $record->isLastPage()}}data-lastPage{{endif}} data-feedID='records{$record::$customDatabaseId}-{$record->_id}' id='comments'>
<template template_key="database_display_comments" template_title="comments" template_desc="" template_location="database" template_group="display" template_params="$record" template_app="" template_type="template"><![CDATA[<div data-controller='core.front.core.commentFeed' {{if settings.auto_polling_enabled}}data-autoPoll{{endif}} data-commentsType='comments' data-baseURL='{$record->url()}' {{if $record->isLastPage()}}data-lastPage{{endif}} data-feedID='records{$record::$customDatabaseId}-{$record->_id}' id='comments'>
<br>
{{if $record->commentPageCount() > 1}}
{$record->commentPagination( array( 'tab' ) )|raw}
@@ -374,7 +725,7 @@
<div class='ipsAreaBackground ipsPad' data-role='replyArea'>
{{if $record->commentForm()}}
{{if $record->locked()}}
<p class='ipsType_reset ipsType_warning ipsComposeArea_warning ipsSpacer_bottom ipsSpacer_half'><i class='fa fa-info-circle'></i> {lang="cms_locked_can_comment"}</p>
<p class='ipsType_reset ipsType_warning ipsComposeArea_warning ipsSpacer_bottom ipsSpacer_half'><i class='fa fa-info-circle'></i> {lang="cms_locked_can_comment" sprintf="$record::database()->recordWord(1)"}</p>
{{endif}}
{$record->commentForm()|raw}
{{else}}
@@ -407,7 +758,8 @@
{{if $record->prefix()}}
{template="prefix" group="global" app="core" params="$record->prefix( TRUE ), $record->prefix()"}
{{endif}}
{{if $record->locked()}}<i class='fa fa-lock'></i> {{endif}}{wordbreak="$record->_title"}
{{if $record->locked()}}<i class='fa fa-lock'></i> {{endif}}
{{if $record->isFutureDate() || $record->mapped('pinned') || $record->mapped('featured') || $record->hidden() === -1 || $record->hidden() === 1}}
{{if $record->isFutureDate()}}
<span class="ipsBadge ipsBadge_icon ipsBadge_warning" data-ipsTooltip title='{$record->futureDateBlurb()}'><i class='fa fa-clock-o'></i></span>
@@ -423,6 +775,8 @@
<span class="ipsBadge ipsBadge_icon ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
{{endif}}
{wordbreak="$record->_title"}
</h1>
{{if $record::database()->options['reviews']}}
@@ -451,7 +805,7 @@
</p>
<ul class='ipsList_inline'>
<li>{datetime="$record->record_publish_date"}</li>
{{foreach $record->customFieldsForDisplay('display') as $fieldId => $fieldValue}}
{{foreach $record->customFieldsForDisplay('display_top') as $fieldId => $fieldValue}}
{{if $fieldValue}}
{$fieldValue|raw}
{{endif}}
@@ -468,17 +822,23 @@
<div class='ipsClearfix'>
{{if $record->record_image}}
<div class="cCmsRecord_image">
<img class="ipsImage" src="{file="$record->record_image" extension="cms_Records"}">
<img class="ipsImage" src="{file="$record->_record_image_thumb" extension="cms_Records"}">
</div>
{{endif}}
<section class="ipsType_richText ipsType_normal" data-controller='core.front.core.lightboxedImages'>{$record->_content|raw}</section>
{{if $record->editLine()}}
{$record->editLine()|raw}
{{endif}}
</div>
{{if $bottomFields = $record->customFieldsForDisplay('display_bottom')}}
<hr class='ipsHr ipsClear ipsClearfix'>
{{foreach $bottomFields as $fieldId => $fieldValue}}
{{if $fieldValue}}
{$fieldValue|raw}
{{endif}}
{{endforeach}}
{{endif}}
<hr class='ipsHr ipsClear ipsClearfix'>
{{if $record instanceof \IPS\Content\Reputation and settings.reputation_enabled}}
@@ -593,11 +953,11 @@
]]></template>
<template template_key="database_display_recordEditLine" template_title="recordEditLine" template_desc="" template_location="database" template_group="display" template_params="$record" template_app="" template_type="template"><![CDATA[
<span class='ipsType_reset ipsType_medium ipsType_light' data-excludequote>
<strong>{lang="date_edited" htmlsprintf="\IPS\DateTime::ts( $record->record_edit_time )->html(FALSE), htmlentities( $record->record_edit_member_name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE )"}</strong>
<strong>{lang="date_edited" htmlsprintf="\IPS\DateTime::ts( $record->record_edit_time )->html(FALSE), htmlspecialchars( $record->record_edit_member_name, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE )"}</strong>
{{if $record->edit_reason}}
<br>{$record->edit_reason}
{{endif}}
{{if \IPS\Settings::i()->edit_log == 2 and ( \IPS\Settings::i()->edit_log_public or \IPS\Member::loggedIn()->modPermission('can_view_editlog') )}}
{{if $record->database()->revisions and \IPS\Settings::i()->edit_log == 2 and ( \IPS\Settings::i()->edit_log_public or \IPS\Member::loggedIn()->modPermission('can_view_editlog') )}}
<a href='{$record->url('revisions')}' data-ipsDialog data-ipsDialog-title="{lang="content_view_revisions"}" title="{lang="content_edit_view_revisions"}">{lang="content_edit_view_revisions"}</a>
{{if !$record->record_edit_show AND \IPS\Member::loggedIn()->modPermission('can_view_editlog')}}
<br>{lang="comment_edit_show_anyways"}
@@ -609,9 +969,12 @@
{template="userPhoto" app="core" group="global" params="$review->author(), 'small', $review->warningRef(), 'ipsPos_left'"}
<div>
<p class='ipsPos_right ipsType_reset ipsType_blendLinks'>
<a href='{$review->item()->url()->setQueryString( array( 'do' => 'findReview', 'review' => $review->id ) )}' data-ipsTooltip title='{lang="share_this_review"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elShareComment_{$review->id}'><i class='fa fa-share-alt'></i></a>
<a href='{$review->item()->url()->setQueryString( array( 'do' => 'findReview', 'review' => $review->id ) )}' data-ipsTooltip title='{lang="share_this_review"}' data-ipsMenu data-ipsMenu-closeOnClick='false' id='elShareComment_{$review->id}' data-role='shareComment'><i class='fa fa-share-alt'></i></a>
{{if count( $item->reviewMultimodActions() )}}
<input type="checkbox" name="multimod[{$review->id}]" value="1" data-role="moderation" data-actions="{{if $review->hidden() === -1 AND $review->canUnhide()}}unhide{{elseif $review->hidden() === 1 AND $review->canUnhide()}}approve{{elseif $review->canHide()}}hide{{endif}} {{if $review->canDelete()}}delete{{endif}}" data-state='{{if $review->tableStates()}}{$review->tableStates()}{{endif}}'>
<span class='ipsCustomInput'>
<input type="checkbox" name="multimod[{$review->id}]" value="1" data-role="moderation" data-actions="{{if $review->hidden() === -1 AND $review->canUnhide()}}unhide{{elseif $review->hidden() === 1 AND $review->canUnhide()}}approve{{elseif $review->canHide()}}hide{{endif}} {{if $review->canDelete()}}delete{{endif}}" data-state='{{if $review->tableStates()}}{$review->tableStates()}{{endif}}'>
<span></span>
</span>
{{endif}}
</p>
<h3 class="ipsComment_author ipsType_blendLinks">
@@ -643,7 +1006,7 @@
</div>
</div>
<div class='ipsPad'>
<div id="review-{$review->id}" data-role="commentContent" class="ipsType_richText ipsType_break ipsContained" itemprop="reviewBody" data-controller='core.front.core.lightboxedImages'>
<div id="review-{$review->id}" data-role="commentContent" class="ipsType_richText ipsType_normal ipsType_break ipsContained" itemprop="reviewBody" data-controller='core.front.core.lightboxedImages'>
{$review->content()|raw}
</div>
@@ -734,7 +1097,7 @@
{template="review" location="database" group="display" app="cms" params="$item, $review, $item::$formLangPrefix . 'review', $item::$application, $item::$module"}
</article>
{{endif}}]]></template>
<template template_key="database_display_reviews" template_title="reviews" template_desc="" template_location="database" template_group="display" template_params="$record" template_app="" template_type="template"><![CDATA[<div data-controller='core.front.core.commentFeed' data-commentsType='reviews' data-baseURL='{$record->url()}' {{if $record->isLastPage('reviews')}}data-lastPage{{endif}} data-feedID='records{$record::$customDatabaseId}-{$record->id}-reviews' id='reviews'>
<template template_key="database_display_reviews" template_title="reviews" template_desc="" template_location="database" template_group="display" template_params="$record" template_app="" template_type="template"><![CDATA[<div data-controller='core.front.core.commentFeed' {{if settings.auto_polling_enabled}}data-autoPoll{{endif}} data-commentsType='reviews' data-baseURL='{$record->url()}' {{if $record->isLastPage('reviews')}}data-lastPage{{endif}} data-feedID='records{$record::$customDatabaseId}-{$record->id}-reviews' id='reviews'>
{{if $record->canReview()}}
{{if $record->locked()}}
<strong class='ipsType_warning'><i class='fa fa-info-circle'></i> {lang="item_locked_can_review"}</strong>
@@ -756,8 +1119,8 @@
{{endif}}
{{endif}}
{{if count( $record->reviews() )}}
<hr class='ipsHr'>
<div class="ipsClearfix ipsSpacer_both">
{{if !$record->hasReviewed()}}<hr class='ipsHr'>{{endif}}
<div class="ipsClearfix ipsSpacer_bottom">
{{if $record->reviewPageCount() > 1}}
<div class="ipsPos_left ipsResponsive_noFloat">
{$record->reviewPagination( array( 'tab', 'sort' ) )|raw}
@@ -795,10 +1158,13 @@
{$record->reviewPagination( array( 'tab', 'sort' ) )|raw}
</div>
{{endif}}
{{elseif !$record->canReview()}}
<p class="ipsType_normal ipsType_light ipsType_reset" data-role="noReviews">{lang="no_reviews"}</p>
{{endif}}
</div>]]></template>
<template template_key="database_form_recordForm" template_title="recordForm" template_desc="" template_location="database" template_group="form" template_params="$record, $category, $database, $page, $title, $hasModOptions, $id, $action, $elements, $hiddenValues, $actionButtons, $uploadField, $class=''" template_app="" template_type="template"><![CDATA[{{$modOptions = array( 'create_record_state', 'record_expiry_date', 'record_pinned', 'record_allow_comments', 'record_comment_cutoff', 'record_meta_keywords', 'record_meta_description' );}}
{template="pageHeader" if="!\IPS\Request::i()->isAjax()" group="global" app="core" params="\IPS\Member::loggedIn()->language()->addToStack( $title )"}
<div id="elCmsPageWrap" data-pageid="{$page->id}">
<form accept-charset='utf-8' class="ipsForm {$class}" data-ipsForm="true" action="{$action}" method="post" {{if $uploadField}}enctype="multipart/form-data"{{endif}}>
<input type="hidden" name="{$id}_submitted" value="1">
{{foreach $hiddenValues as $k => $v}}
@@ -905,7 +1271,7 @@
</div>
<div class='ipsColumn ipsColumn_wide'>
<div class='ipsPad ipsAreaBackground_light'>
<h3 class='ipsType_sectionHead'>{lang="topic_moderator_options"}</h3>
<h3 class='ipsType_sectionHead'>{lang="cms_moderator_options"}</h3>
<ul class='ipsForm ipsForm_vertical ipsSpacer_top'>
{{foreach $elements as $collection}}
{{foreach $collection as $inputName => $input}}
@@ -941,7 +1307,8 @@
<button type='submit' class='ipsButton ipsButton_large ipsButton_primary'>{lang="content_record_form_save"}</button>
</div>
</div>
</form>]]></template>
</form>
</div>]]></template>
<template template_key="database_listing_categoryFooter" template_title="categoryFooter" template_desc="" template_location="database" template_group="listing" template_params="$category, $table, $activeFilters" template_app="" template_type="template"><![CDATA[
{{if ! \IPS\Request::i()->isAjax() AND ! isset( \IPS\Request::i()->advancedSearchForm ) AND $category->show_records}}
<ul class="ipsToolList ipsToolList_horizontal ipsClearfix ipsSpacer_both ipsResponsive_showPhone ipsResponsive_block">
@@ -1205,6 +1572,24 @@
{{if $row->locked()}}
<i class='fa fa-lock' data-ipsTooltip title='{lang="content_locked_record"}'></i>
{{endif}}
{{if $row->isFutureDate() || $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}}
<span>
{{if $row->isFutureDate()}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->futureDateBlurb()}'><i class='fa fa-clock-o'></i></span>
{{elseif $row->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $row->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $row->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $row->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
</span>
{{endif}}
{{if $row->prefix()}}
{template="prefix" group="global" app="core" params="$row->prefix( TRUE ), $row->prefix()"}
@@ -1214,23 +1599,7 @@
{{if $row->_title}}{$row->_title}{{else}}<em class="ipsType_light">{lang="content_deleted"}</em>{{endif}}
</a>
</h4>
{{if $row->isFutureDate() || $row->mapped('pinned') || $row->mapped('featured') || $row->hidden() === -1 || $row->hidden() === 1}}
<span>
{{if $row->isFutureDate()}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->futureDateBlurb()}'><i class='fa fa-clock-o'></i></span>
{{elseif $row->hidden() === -1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{$row->hiddenBlurb()}'><i class='fa fa-eye-slash'></i></span>
{{elseif $row->hidden() === 1}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_warning" data-ipsTooltip title='{lang="pending_approval"}'><i class='fa fa-warning'></i></span>
{{endif}}
{{if $row->mapped('pinned')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="pinned"}'><i class='fa fa-thumb-tack'></i></span>
{{endif}}
{{if $row->mapped('featured')}}
<span class="ipsBadge ipsBadge_icon ipsBadge_small ipsBadge_positive" data-ipsTooltip title='{lang="featured"}'><i class='fa fa-star'></i></span>
{{endif}}
</span>
{{endif}}
{{if $row->commentPageCount() > 1}}
{$row->commentPagination( array(), 'miniPagination' )|raw}
{{endif}}
@@ -1243,8 +1612,8 @@
{{endforeach}}
</div>
{{endif}}
<div class='ipsDataItem_meta'>
<p class='ipsType_reset ipsType_light'>{lang="byline" sprintf="$row->author()->name"}{datetime="$row->_publishDate"}</p>
<div class='ipsDataItem_meta ipsType_blendLinks'>
<p class='ipsType_reset ipsType_light'>{lang="byline" htmlsprintf="$row->author()->link( $row->warningRef() )"}{datetime="$row->_publishDate"}</p>
</div>
</div>
<ul class='ipsDataItem_stats'>
@@ -1266,7 +1635,7 @@
</li>
{{endif}}
</ul>
<ul class='ipsDataItem_lastPoster ipsDataItem_withPhoto'>
<ul class='ipsDataItem_lastPoster ipsDataItem_withPhoto ipsType_blendLinks'>
{{if $row::database()->options['comments'] or $row::database()->options['reviews']}}
<li>
{{if $row->mapped('num_comments')}}
@@ -1284,7 +1653,7 @@
</li>
<li class="ipsType_light">
<a href='{$row->url( 'getLastComment' )}' title='{lang="get_last_post"}' class='ipsType_blendLinks'>
<a href='{$row->url( 'getLastComment' )}' title='{lang="get_last_post"}'>
{{if $row->mapped('num_comments')}}{datetime="$row->mapped('last_comment')"}{{else}}{datetime="$row->mapped('date')"}{{endif}}
</a>
</li>
@@ -1304,11 +1673,16 @@
</ul>
{{if $table and $table->canModerate()}}
<div class='ipsDataItem_modCheck'>
<input type='checkbox' data-role='moderation' name="moderate[{$row->$idField}]" data-actions="{expression="implode( ' ', $table->multimodActions( $row ) )"}" data-state='{{if $row->tableStates()}}{$row->tableStates()}{{endif}}'>
<span class='ipsCustomInput'>
<input type='checkbox' data-role='moderation' name="moderate[{$row->$idField}]" data-actions="{expression="implode( ' ', $table->multimodActions( $row ) )"}" data-state='{{if $row->tableStates()}}{$row->tableStates()}{{endif}}'>
<span></span>
</span>
</div>
{{endif}}
</li>
{{endforeach}}]]></template>
<template template_key="database_listing_rssItemWithImage" template_title="rssItemWithImage" template_desc="" template_location="database" template_group="listing" template_params="$content, $image" template_app="" template_type="template"><![CDATA[<p><img src="{file="$image" extension="cms_Records"}" /></p>
{$content|raw}]]></template>
<template template_key="page_page_builder_single_column" template_title="single_column" template_desc="" template_location="page" template_group="page_builder" template_params="$page, $widgets" template_app="" template_type="template"><![CDATA[<div>
{template="widgetContainer" group="pages" app="cms" params="'col1', $widgets, 'horizontal'"}
</div>]]></template>
+4 -4
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<emails><template><template_app>cms</template_app><template_name>digests__comment</template_name><template_content_html><![CDATA[<tr style='border-bottom: 1px solid #eeeeee'>
<td width='40' align='center' valign='top' class=' '>
<td dir='{dir}' width='40' align='center' valign='top' class=' '>
<img src='{$comment->author()->photo}' width='32' height='32' style='border: 1px solid #000; vertical-align: middle;'>
</td>
<td align='left'>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
{{$item = $comment->item();}}
({$email->language->addToStack("x_commented_cms", FALSE, array( 'sprintf' => array( $comment->author()->name, $item::database()->recordWord( 1 ) ) ) )})
@@ -18,10 +18,10 @@
</tr>]]></template_content_html><template_data>$comment, $email</template_data><template_content_plaintext><![CDATA[{{$item = $comment->item();}}
{$email->language->addToStack("x_commented_cms", FALSE, array( 'sprintf' => array( $comment->author()->name, $item::database()->recordWord( 1 ) ) ) )}: {$comment->item()->_title} ({$comment->url()})
]]></template_content_plaintext></template><template><template_app>cms</template_app><template_name>digests__item</template_name><template_content_html><![CDATA[<tr style='border-bottom: 1px solid #eeeeee'>
<td width='40' align='center' valign='top' class=' '>
<td dir='{dir}' width='40' align='center' valign='top' class=' '>
<img src='{$entry->author()->photo}' width='32' height='32' style='border: 1px solid #000; vertical-align: middle;'>
</td>
<td align='left'>
<td dir='{dir}' align='left'>
<p style='font-family: "Helvetica Neue", helvetica, sans-serif; margin: 0; font-size: 13px; font-weight: bold'>
{$email->language->addToStack("x_created_cms_in", FALSE, array( 'sprintf' => array( $entry->author()->name, $entry::database()->recordWord( 1 ), $entry->container()->_title ) ) )}
</p>
+773 -16
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<javascript app="cms">
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/blocks" javascript_name="ips.blocks.form.js" javascript_type="controller" javascript_version="100045" javascript_position="1000050"><![CDATA[/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/blocks" javascript_name="ips.blocks.form.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -118,7 +118,7 @@
var save = { 't_location': 'block', 't_key': this.scope.find('#elSelect_block_template_id').val(), 'block_key': this.scope.find('input[name=block_plugin]').val(), 'block_app': this.scope.find('input[name=block_plugin_app]').val() };
var self = this;
ips.getAjax()( '?app=cms&module=pages&controller=ajax&do=loadTemplate&show=json', {
ips.getAjax()( '?app=cms&module=pages&controller=ajax&do=loadTemplate&show=json&noencode=1', {
dataType: 'json',
data: save,
type: 'post'
@@ -133,7 +133,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/databases" javascript_name="ips.databases.download.js" javascript_type="controller" javascript_version="100045" javascript_position="1000100">/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/databases" javascript_name="ips.databases.download.js" javascript_type="controller" javascript_version="101012" javascript_position="1000100">/**
* IPS Social Suite 4
* (c) 2014 Invision Power Services - http://www.invisionpower.com
*
@@ -178,7 +178,7 @@
}
});
}(jQuery, _));</file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/databases" javascript_name="ips.databases.form.js" javascript_type="controller" javascript_version="100045" javascript_position="1000100">/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/databases" javascript_name="ips.databases.form.js" javascript_type="controller" javascript_version="101012" javascript_position="1000100">/**
* IPS Social Suite 4
* (c) 2014 Invision Power Services - http://www.invisionpower.com
*
@@ -241,7 +241,142 @@
}
});
}(jQuery, _));</file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/fields" javascript_name="ips.fields.form.js" javascript_type="controller" javascript_version="100045" javascript_position="1000150">/**
<file javascript_app="cms" javascript_location="front" javascript_path="controllers/external" javascript_name="ips.external.communication.js" javascript_type="controller" javascript_version="101012" javascript_position="1000050"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.external.communication.js - External communication widget - sends messages to the parent window
*
* Author: Rikki Tissier
*/
;( function($, _, undefined){
"use strict";
ips.controller.register('cms.front.external.communication', {
_blockID: '',
_widgetID: '',
initialize: function () {
this.on( window, 'message', this.windowMessage );
this.on( 'click', 'a', this.clickLink );
this.setup();
},
/**
* setup method
*
* @returns {void}
*/
setup: function () {
var self = this;
var url = ips.utils.url.getURIObject();
this._blockID = url.queryKey.blockid;
this._widgetID = url.queryKey.widgetid;
this._send( 'iframeReady' );
this._sendHeight();
// We'll run a loop to track the height of the document and let the parent know
setInterval( _.bind( this._sendHeight, this ), 500 );
},
/**
* Handles messages received from the parent window
*
* @param {event} e Event object
* @returns {void}
*/
windowMessage: function (e) {
try {
var pmData = JSON.parse( e.originalEvent.data );
var method = pmData.method;
} catch (err) {
return;
}
// Check we have a widget ID and it matches ours
if( _.isUndefined( pmData.widgetID ) || pmData.widgetID !== this._widgetID ){
return;
}
if( method && !_.isUndefined( this[ method ] ) ){
this[ method ].call( this, pmData );
}
},
/**
* The parent has sent us some styles to use
*
* @param {object} data Data object containing the styles
* @returns {void}
*/
probedStyles: function (data) {
// Create a style element to insert into the head
var elem = $('<style/>').attr('type', 'text/css').appendTo('head');
var stylesheet = "\
body {\
font-family: " + data.font + "; \
color: " + data.text + ";\
}\
\
a {\
color: " + data.link + ";\
}\
";
elem.text( stylesheet );
},
/**
* Event handler for clicking a link; we'll send it to the parent to handle
*
* @param {event} e Event object
* @returns {void}
*/
clickLink: function (e) {
var link = $( e.currentTarget );
var href = link.attr('href');
if( href.startsWith('#') ){
return;
}
e.preventDefault();
this._send( 'goToLink', { link: href } );
},
/**
* Shortcut for calculating and sending the height to the parent
*
* @returns {void}
*/
_sendHeight: function () {
var currentSize = $('body').outerHeight();
this._send( 'iframeSize', { size: currentSize } );
},
/**
* Sends a message to the parent
*
* @param {string} method Method name to call on the parent
* @param {object} data Data object to send
* @returns {void}
*/
_send: function (method, data) {
var output = JSON.stringify( _.extend( data || {}, {
method: method,
widgetID: this._widgetID,
blockID: this._blockID
}));
window.top.postMessage( output, '*' );
}
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/fields" javascript_name="ips.fields.form.js" javascript_type="controller" javascript_version="101012" javascript_position="1000150">/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -278,7 +413,612 @@
}
});
}(jQuery, _));</file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/pages" javascript_name="ips.pages.form.js" javascript_type="controller" javascript_version="100045" javascript_position="1000200"><![CDATA[/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/media" javascript_name="ips.media.main.js" javascript_type="controller" javascript_version="101012" javascript_position="1000200"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.media.main.js - Main media controller
*
* Author: Rikki Tissier
*/
;( function($, _, undefined){
"use strict";
ips.controller.register('cms.admin.media.main', {
_fileListing: null,
_sidebar: null,
_folderListing: null,
_cachedFileInfo: {},
_cachedFolders: {},
_folderAjax: null,
_searchTimer: null,
_uploadURL: '',
initialize: function () {
this.on( 'click', '[data-role="mediaItem"]', this.clickItem );
this.on( 'click', '[data-role="fileListing"]', this.clickWrapper );
this.on( 'click', '[data-role="mediaFolder"] > a', this.clickMediaFolder );
this.on( 'click', '[data-action="deleteSelected"]', this.deleteSelected );
this.on( 'keydown', '[data-role="mediaSearch"]', this.searchKeyPress );
this.on( 'submitDialog', '[data-role="uploadButton"]', this.dialogSubmitted );
this.setup();
},
/**
* Setup method
*
* @returns {void}
*/
setup: function () {
this._fileListing = this.scope.find('[data-role="fileListing"]');
this._searchResults = this.scope.find('[data-role="searchResults"]');
this._sidebar = this.scope.find('[data-role="mediaSidebar"]');
this._folderListing = this.scope.find('[data-role="folderList"]');
this._uploadURL = this.scope.find('[data-role="uploadButton"]').attr('href');
this._newFolderURL = this.scope.find('[data-role="folderButton"]').attr('href');
this.scope.find('[data-role="uploadButton"]').attr('href', this._uploadURL + '&media_parent=0' );
this.scope.find('[data-role="folderButton"]').attr('href', this._newFolderURL + '&media_parent=0' );
},
/**
* Dialog submit handler from uploading process
* The dialog response will include an array of media items in this folder. We'll use
* this data to rebuild the file listing, thereby showing the new files immediately.
*
* @param {event} e Event object
* @param {object} data Event data object
* @returns {void}
*/
dialogSubmitted: function (e, data) {
var newHTML = [];
var folderID = data.response.folderID;
_.each( data.response.rows, function (file, key) {
newHTML.push( file );
});
this._cachedFolders[ folderID ] = newHTML;
this._buildFileListing( folderID, newHTML );
ips.ui.flashMsg.show( ips.pluralize( ips.getString('mediaUploadedCount'), data.response.count ) );
},
/**
* keypress event handler for the search text box
*
* @param {event} e Event object
* @returns {void}
*/
searchKeyPress: function (e) {
clearTimeout( this._searchTimer );
this._searchTimer = setTimeout( _.bind( this._doSearch, this ), 500 );
},
/**
* Event handler for clicking a folder in the list
*
* @param {event} e Event object
* @returns {void}
*/
clickMediaFolder: function (e) {
e.preventDefault();
var self = this;
var allRows = this._folderListing.find('[data-role="mediaFolder"]');
var row = $( e.currentTarget ).closest('[data-role="mediaFolder"]');
var rowURL = row.find('> a').attr('href');
var rowID = row.attr('data-folderID');
this._resetSearch();
if( row.hasClass('ipsTreeList_activeBranch') ){
row
.removeClass('ipsTreeList_activeBranch')
.addClass('ipsTreeList_inactiveBranch');
} else {
row
.removeClass('ipsTreeList_inactiveBranch')
.addClass('ipsTreeList_activeBranch');
}
allRows.removeClass('ipsTreeList_activeNode');
row.addClass('ipsTreeList_activeNode');
// Update the upload/new folder buttons
this.scope.find('[data-role="uploadButton"]').attr('href', this._uploadURL + '&media_parent=' + rowID );
this.scope.find('[data-role="folderButton"]').attr('href', this._newFolderURL + '&media_parent=' + rowID );
// Load subfolders
this._loadFolders( rowID, rowURL );
// And folder contents
this._loadFiles( rowID, rowURL );
this._unselectAll();
this._updatePreview();
this._checkDeleteButton();
},
/**
* Prompts and deletes selected files
*
* @param {event} e Event object
* @returns {void}
*/
deleteSelected: function (e) {
var self = this;
var selected = this._getSelected().closest('[data-role="mediaItem"]');
var selectedIDs = [];
$.each( selected, function () {
selectedIDs.push( $( this ).attr('data-fileid') );
});
// Confirm with user
ips.ui.alert.show({
type: 'confirm',
message: ips.pluralize( ips.getString('mediaConfirmDelete'), selected.length ),
icon: 'warn',
callbacks: {
ok: function () {
selected.find('.cMedia_itemSelected').removeClass('cMedia_itemSelected')
// Hide and remove them
ips.utils.anim.go( 'fadeOutDown', selected )
.done( function () {
selected.remove();
self._updatePreview();
self._checkDeleteButton();
});
// Delete them on the server
ips.getAjax()( '?app=cms&module=pages&controller=media&do=deleteByFileIds', {
data: {
fileIds: selectedIDs
}
})
.fail( function () {
ips.ui.alert.show({
type: 'alert',
message: ips.pluralize( ips.getString('mediaErrorDeleting'), selected.length )
});
})
}
}
});
},
/**
* Event handler for clicking in the whitepace of the file listing
* Unselects any selected files
*
* @param {event} e Event object
* @returns {void}
*/
clickWrapper: function (e) {
if( !$( e.target ).closest('[data-role="mediaItem"]').length ) {
this._unselectAll();
this._updatePreview();
this._checkDeleteButton();
}
},
/**
* Event handler for clicking a file in the file listing
* Modifier keys change how we handle the selection in order to mimic file managers
*
* @param {event} e Event object
* @returns {void}
*/
clickItem: function (e) {
var item = $( e.currentTarget ).find('> .cMedia_item');
var metaPressed = e.metaKey;
var shiftPressed = e.shiftKey;
if( !metaPressed && !shiftPressed ){
// If no special keys are pressed, unhighlight all and highlight this one
this._unselectAll();
item.addClass('cMedia_itemSelected');
this._switchToTab('overview');
} else if( metaPressed ) {
// If meta key is pressed, toggle the state of the clicked image
item.toggleClass( 'cMedia_itemSelected', ( !item.hasClass('cMedia_itemSelected') ) );
} else if( shiftPressed ) {
// If shift is pressed, select the whole run
// Find the first selected file
var all = this._fileListing.find('.cMedia_item');
var indexOfFirst = all.index( all.filter('.cMedia_itemSelected').first() );
var indexOfClicked = all.index( item );
var itemsToSelect = null;
// Unselect all to start with
this._unselectAll();
// Select the run
if( indexOfFirst == indexOfClicked ){
itemsToSelect = item;
} else if( indexOfFirst < indexOfClicked ){
itemsToSelect = all.slice( indexOfFirst, indexOfClicked ).addBack( item );
} else if( indexOfFirst > indexOfClicked ){
itemsToSelect = all.slice( indexOfClicked, indexOfFirst + 1 );
}
itemsToSelect.addClass('cMedia_itemSelected');
}
this._updatePreview();
this._checkDeleteButton();
},
/**
* Checks whether any files are selected and displays the delete button if so
*
* @returns {void}
*/
_checkDeleteButton: function () {
var selected = this._getSelected().closest('[data-role="mediaItem"]');
if( selected.length == 0 ){
this.scope.find('[data-action="deleteSelected"]').addClass('ipsHide');
} else {
this.scope.find('[data-action="deleteSelected"]').removeClass('ipsHide');
}
},
/**
* Loads sub-folders of the given folder id
*
* @param {number} rowID Folder row ID to load
* @param {string} url Url for this folder
* @returns {void}
*/
_loadFolders: function (rowID, url) {
var self = this;
var row = this._folderListing.find('[data-folderID="' + rowID + '"]');
if( this._folderAjax && _.isFunction( this._folderAjax.abort ) ){
this._folderAjax.abort();
}
// If this row is loaded, we can just show it
if( row.attr('data-loaded') ){
return;
}
this._folderAjax = ips.getAjax()( url, {
data: {
get: 'folders'
}
} )
.done( function (response) {
var subFolder = row.find('ul');
var newHTML = [];
_.each( response, function (folder, key) {
newHTML.push( folder );
});
subFolder.html( newHTML.join('') );
row.attr('data-loaded', true);
});
},
/**
* Loads files inside the given folder ID
*
* @param {number} folderID Folder row ID to load
* @param {string} url Url for this folder
* @returns {void}
*/
_loadFiles: function (folderID, url) {
var self = this;
if( this._filesAjax && _.isFunction( this._filesAjax.abort ) ){
this._filesAjax.abort();
}
// Are we already viewing this folder?
if( this._fileListing.attr('data-showing') == folderID ){
return;
}
// Do we have a cache already?
if( !_.isUndefined( this._cachedFolders[ folderID ] ) ){
this._buildFileListing( folderID, this._cachedFolders[ folderID ] );
return;
}
// No cache, so load the file listing
this._fileListing.addClass('ipsLoading').html('');
ips.getAjax()( url, {
data: {
get: 'files'
}
} )
.done( function (response) {
var newHTML = [];
_.each( response, function (file, key) {
newHTML.push( file );
});
self._cachedFolders[ folderID ] = newHTML;
self._buildFileListing( folderID, newHTML );
})
.always( function () {
self._fileListing.removeClass('ipsLoading');
});
},
/**
* Builds the file listing for the given folder ID from the given data
*
* @param {number} folderID Folder row ID to build
* @param {array} data Array of file item HTML fragments
* @returns {void}
*/
_buildFileListing: function (folderID, data) {
var output;
if( !data.length ){
output = ips.templates.render('templates.media.noItems');
} else {
output = ips.templates.render( 'templates.media.grid', {
contents: data.join('')
});
}
this._fileListing.attr( 'data-showing', folderID ).html( output );
$( document ).trigger( 'contentChange', [ this._fileListing ] );
},
/**
* Updates the preview panel in the sidebar by finding the selected item and extracting
* relevant information about it to display
*
* @returns {void}
*/
_updatePreview: function () {
// How many selected?
var self = this;
var selected = this._getSelected().closest('[data-role="mediaItem"]');
if( selected.length == 0 || selected.length > 1 ){
// Build the string
var language = ( selected.length == 0 ) ? ips.getString('mediaNoneSelected') : ips.pluralize( ips.getString('mediaMultipleSelected'), selected.length );
// Insert it
this._sidebar.find('[data-role="multipleItemsMessage"]').html( language );
// Show the message box
this._sidebar.find('[data-role="itemInformation"]').hide().end().find('[data-role="multipleItems"]').show();
} else {
// Build the file info
var info = {
itemFilename: selected.attr('data-filename'),
itemUploaded: selected.attr('data-uploaded'),
itemTag: '{media="' + selected.attr('data-path') + '"}',
itemID: selected.attr('data-fileid'),
itemIsImage: selected.is('[data-isImage]'),
itemFilesize: null,
itemDimensions: null
};
// Dimensions & filesize
var cache = this._cachedFileInfo[ info.itemID ];
if( !_.isUndefined( cache ) ){
info.itemFilesize = cache['itemFilesize'];
info.itemDimensions = cache['itemDimensions'];
} else {
// Do ajax
this._infoAjax = ips.getAjax()( '?app=cms&module=pages&controller=media&do=getFileInfo&id=' + info.itemID )
.done( function (response) {
self._cachedFileInfo[ info.itemID ] = {
itemFilesize: response.fileSize,
itemDimensions: response.dimensions
};
self._sidebar.find('[data-role="itemFilesize"]').text( response.fileSize );
self._sidebar.find('[data-role="itemDimensions"]').text( response.dimensions );
});
}
// Build thumbnail
if( info.itemIsImage ){
info.itemPreview = $('<img/>').attr( 'src', selected.attr('data-url') ).attr('data-ipsLightbox', true );
} else {
info.itemPreview = $('<div/>').addClass('ipsNoThumb');
}
// Update the easy info
_.each( info, function (value, key) {
var elem = self._sidebar.find('[data-role="' + key + '"]');
if( !elem.length ){
return;
}
if( elem.is('input') ){
elem.val( value );
} else if( key == 'itemPreview' ) {
elem.html( value );
} else if( value === null ){
elem.html( $('<span/>').addClass('ipsType_light').text('Loading...') );
} else {
elem.text( value );
}
});
// If this is an image, show the dimensions row
this._sidebar.find('[data-role="itemDimensionsRow"]').toggle( info.itemIsImage );
// Pre-select the tag box
this._sidebar.find('[data-role="itemTag"]').get(0).select();
// Hide the 'multiple items selected' div and show our info div
this._sidebar.find('[data-role="itemInformation"]').show().end().find('[data-role="multipleItems"]').hide();
$( document ).trigger( 'contentChange', [ this._sidebar ] );
}
},
/**
* Performs a tree search and displays results
*
* @returns {void}
*/
_doSearch: function () {
if( this._searchAjax && _.isFunction( this._searchAjax.abort ) ){
this._searchAjax.abort();
}
var self = this;
var value = this.scope.find('[data-role="mediaSearch"]').val();
if( !_.isEmpty( value ) ){
this._searchResults.show().addClass('ipsLoading');
this._fileListing.hide();
this._folderListing.addClass('cMedia_treeDisabled');
this._searchAjax = ips.getAjax()( '?app=cms&module=pages&controller=media&do=search', {
data: {
input: value
}
})
.done( function (response) {
var newHTML = [];
var output = '';
_.each( response, function (file, key) {
newHTML.push( file );
});
if( !newHTML.length ){
output = ips.templates.render('templates.media.noSearchResults');
} else {
output = ips.templates.render( 'templates.media.grid', {
contents: newHTML.join('')
});
}
self._searchResults.removeClass('ipsLoading').html( output );
$( document ).trigger( 'contentChange', [ self._searchResults ] );
self._unselectAll();
self._updatePreview();
self._checkDeleteButton();
})
} else {
this._searchResults.hide().html('');
this._fileListing.show();
this._folderListing.removeClass('cMedia_treeDisabled');
this._updatePreview();
this._checkDeleteButton();
}
},
/**
* Returns selected files, from the file listing or search results panels depending
* on which is active
*
* @returns {object} jQuery collection of selected files
*/
_getSelected: function () {
if( this._fileListing.is(':visible') ){
return this._fileListing.find('.cMedia_itemSelected');
} else {
return this._searchResults.find('.cMedia_itemSelected');
}
},
/**
* Resets the search box, hiding the results in the process
*
* @returns {void}
*/
_resetSearch: function () {
this.scope.find('[data-role="mediaSearch"]').val('');
this._searchResults.hide();
this._fileListing.show();
this._unselectAll();
this._updatePreview();
this._checkDeleteButton();
},
/**
* Unselects all files
*
* @returns {void}
*/
_unselectAll: function () {
this._fileListing.find('.cMedia_item').removeClass('cMedia_itemSelected');
this._searchResults.find('.cMedia_item').removeClass('cMedia_itemSelected');
},
/**
* Switches the sidebar to the given tab
*
* @param {string} tab Tab to switch to
* @returns {void}
*/
_switchToTab: function (tab) {
if( tab == 'overview' ){
this.scope.find('#elTab_overview').click();
}
}
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/pages" javascript_name="ips.pages.embed.js" javascript_type="controller" javascript_version="101012" javascript_position="1000250"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
* ips.pages.embed.js - Pages embed dialog
*
* Author: Rikki Tissier
*/
;( function($, _, undefined){
"use strict";
ips.controller.register('cms.admin.pages.embed', {
initialize: function () {
this.on( 'change', 'input[type="checkbox"]', this.toggleInherit );
this.on( 'mouseenter', 'textarea', this.mouseEnterTextarea );
},
/**
* Event handler for mousing over the textareas - we'll select hem to make them easy to copy and paste
*
* @param {event} e Event object
* @returns {void}
*/
mouseEnterTextarea: function (e) {
$( e.currentTarget ).select();
},
/**
* Event handler for toggling the 'inherit styles' check
*
* @param {event} e Event object
* @returns {void}
*/
toggleInherit: function (e) {
var toggle = this.scope.find('input[type="checkbox"]');
var textbox = this.scope.find('[data-role="blockCode"]');
if( toggle.is(':checked') ){
textbox.val( textbox.val().replace("></div>", " data-inheritStyle='true'></div>") );
} else {
textbox.val( textbox.val().replace(" data-inheritStyle='true'></div>", "></div>") );
}
}
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/pages" javascript_name="ips.pages.form.js" javascript_type="controller" javascript_version="101012" javascript_position="1000250"><![CDATA[/**
* IPS Social Suite 4
* (c) 2014 Invision Power Services - http://www.invisionpower.com
*
@@ -371,7 +1111,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="front" javascript_path="controllers/records" javascript_name="ips.records.form.js" javascript_type="controller" javascript_version="100045" javascript_position="1000050"><![CDATA[/**
<file javascript_app="cms" javascript_location="front" javascript_path="controllers/records" javascript_name="ips.records.form.js" javascript_type="controller" javascript_version="101012" javascript_position="1000100"><![CDATA[/**
* IPS Social Suite 4
* (c) 2014 Invision Power Services - http://www.invisionpower.com
*
@@ -483,7 +1223,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.addForm.js" javascript_type="controller" javascript_version="100045" javascript_position="1000250">/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.addForm.js" javascript_type="controller" javascript_version="101012" javascript_position="1000300">/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -533,7 +1273,7 @@
}
});
}(jQuery, _));</file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.conflict.js" javascript_type="controller" javascript_version="100045" javascript_position="1000250">/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.conflict.js" javascript_type="controller" javascript_version="101012" javascript_position="1000300">/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -605,7 +1345,7 @@
}
});
}(jQuery, _));</file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.fileEditor.js" javascript_type="controller" javascript_version="100045" javascript_position="1000250"><![CDATA[/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.fileEditor.js" javascript_type="controller" javascript_version="101012" javascript_position="1000300"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -1458,7 +2198,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.fileList.js" javascript_type="controller" javascript_version="100045" javascript_position="1000250"><![CDATA[/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.fileList.js" javascript_type="controller" javascript_version="101012" javascript_position="1000300"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -1778,7 +2518,7 @@
}
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.main.js" javascript_type="controller" javascript_version="100045" javascript_position="1000250">/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.main.js" javascript_type="controller" javascript_version="101012" javascript_position="1000300">/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -1819,7 +2559,7 @@
});
}(jQuery, _));</file>
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.variablesDialog.js" javascript_type="controller" javascript_version="100045" javascript_position="1000250">/**
<file javascript_app="cms" javascript_location="admin" javascript_path="controllers/templates" javascript_name="ips.templates.variablesDialog.js" javascript_type="controller" javascript_version="101012" javascript_position="1000300">/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -1857,7 +2597,7 @@
}
});
}(jQuery, _));</file>
<file javascript_app="cms" javascript_location="front" javascript_path="mixins" javascript_name="ips.cms.builder.area.js" javascript_type="mixins" javascript_version="100045" javascript_position="1000100"><![CDATA[/**
<file javascript_app="cms" javascript_location="front" javascript_path="mixins" javascript_name="ips.cms.builder.area.js" javascript_type="mixins" javascript_version="101012" javascript_position="1000150"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -1923,7 +2663,7 @@
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="front" javascript_path="mixins" javascript_name="ips.cms.builder.block.js" javascript_type="mixins" javascript_version="100045" javascript_position="1000100"><![CDATA[/**
<file javascript_app="cms" javascript_location="front" javascript_path="mixins" javascript_name="ips.cms.builder.block.js" javascript_type="mixins" javascript_version="101012" javascript_position="1000150"><![CDATA[/**
* IPS Social Suite 4
* (c) 2013 Invision Power Services - http://www.invisionpower.com
*
@@ -2029,7 +2769,24 @@
});
}(jQuery, _));]]></file>
<file javascript_app="cms" javascript_location="admin" javascript_path="templates" javascript_name="ips.templates.templates.js" javascript_type="template" javascript_version="100045" javascript_position="1000250"><![CDATA[/* TEMPLATE EDITOR TEMPLATES */
<file javascript_app="cms" javascript_location="admin" javascript_path="templates" javascript_name="ips.templates.media.js" javascript_type="template" javascript_version="101012" javascript_position="1000300"><![CDATA[ips.templates.set( 'templates.media.grid', "\
<ul class='ipsGrid' data-ipsGrid data-ipsGrid-minItemSize='100' data-ipsGrid-maxItemSize='200'>\
{{{contents}}}\
</ul>\
");
ips.templates.set( 'templates.media.noItems', "\
<div class='ipsType_center ipsType_large ipsType_light ipsPad_double'>\
{{#lang}}mediaEmptyFolder{{/lang}}\
</div>\
");
ips.templates.set( 'templates.media.noSearchResults', "\
<div class='ipsType_center ipsType_large ipsType_light ipsPad_double'>\
{{#lang}}mediaNoResults{{/lang}}\
</div>\
");]]></file>
<file javascript_app="cms" javascript_location="admin" javascript_path="templates" javascript_name="ips.templates.templates.js" javascript_type="template" javascript_version="101012" javascript_position="1000300"><![CDATA[/* TEMPLATE EDITOR TEMPLATES */
/* TEMPLATECEPTION */
ips.templates.set('templates.editor.newTab', " \
<li data-fileid='{{fileid}}' data-location='{{location}}'>\
+88 -32
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<language>
<app key="cms" version="100045">
<app key="cms" version="101012">
<word key="__app_cms" js="0">Pages</word>
<word key="menutab__cms" js="0">Pages</word>
<word key="menutab__cms_icon" js="0">book</word>
@@ -9,6 +9,7 @@
<word key="__indefart_content_record_reviews_title" js="0">a review</word>
<word key="rebuilding_cms_database_categories" js="0">Rebuilding %s categories</word>
<word key="rebuilding_cms_database_records" js="0">Rebuilding %s records</word>
<word key="module_no_permission" js="0">No permission</word>
<word key="sitemap_cms_Databases" js="0">Database Records</word>
<word key="sitemap_cms_Pages" js="0">Pages</word>
<word key="sitemap_databases_count" js="0">Number of records to include</word>
@@ -77,6 +78,7 @@
<word key="editor__cms_PageContent" js="0">CMS Pages</word>
<word key="filestorage__cms_Records" js="0">CMS Records</word>
<word key="filestorage__cms_Pages" js="0">CMS Pages</word>
<word key="filestorage__cms_Media" js="0">CMS Media</word>
<word key="modperms__cms_Databases" js="0">Databases</word>
<word key="can_content_revisions_content" js="0">Can Manage Revisions</word>
<word key="can_content_edit_meta_tags" js="0">Can manage meta tags</word>
@@ -141,13 +143,15 @@
<word key="cms_block_preview_refresh" js="0">Refresh Preview</word>
<word key="cms_db_feed_title" js="0">Database Feeds</word>
<word key="cms_db_feed_block_with_name" js="0">Feed from %s</word>
<word key="cms_db_feed_block_with_name_disabled" js="0">Cannot create a feed for %s as this database is not assigned to a page</word>
<word key="cms_block_form_display" js="0">Templates</word>
<word key="block_key" js="0">Template Key</word>
<word key="block_key_desc" js="0"><![CDATA[<p class='ipsMessage ipsMessage_info'>The block key can be used in HTML templates and manual pages to fetch a specific block, for instance: <span class='ipsType_monospace'>{block="my_block_key"}</span></p><br>The key must be unique for this database. If omitted, a key will be automatically generated.]]></word>
<word key="block_key_desc" js="0"><![CDATA[<p class='ipsMessage ipsMessage_info'>The block key ('my_block_key') can be used in HTML templates and manual pages to fetch a specific block, for instance: <span class='ipsType_monospace'>{block="my_block_key"}</span></p><br>The key must be unique for this database. If omitted, a key will be automatically generated.]]></word>
<word key="cms_block_key_not_unique" js="0">The block key is not unique</word>
<word key="save_and_reload" js="0">Save and Reload</word>
<word key="block_cache" js="0">Cache this block</word>
<word key="block_cache_desc" js="0">If your block contains dynamic elements, such as member data, database counts, etc, you will need to prevent this block from being cached.</word>
<word key="content_record_title_pl" js="0">Records</word>
<word key="content_template_type_block" js="0">Block Plugin Templates</word>
<word key="content_template_type_page" js="0">Page Templates</word>
<word key="content_template_type_css" js="0">Page CSS</word>
@@ -196,6 +200,15 @@
<word key="template_group_existing" js="0">Existing Group</word>
<word key="template_group_new" js="0">New Group</word>
<word key="cms_theme_designer_mode_warning" js="0"><![CDATA[Theme editing is currently unavailabe in the ACP as you have designers' mode enabled.<br /><a href='%s'>Switch off designers' mode.</a>]]></word>
<word key="cms_templates_export_title" js="0">Download Templates</word>
<word key="cms_templates_export_description" js="0">Select the templates to export from the list below. These templates will be added to a single XML file that can be imported to other IPS4 communities.</word>
<word key="templates_block" js="0">Blocks</word>
<word key="templates_database" js="0">Database</word>
<word key="templates_page" js="0">Pages</word>
<word key="cms_no_templates_selected" js="0">You must select templates to export</word>
<word key="cms_templates_import_title" js="0">Upload Templates</word>
<word key="cms_templates_import" js="0">Upload</word>
<word key="cms_templates_imported" js="0">Templates Imported</word>
<word key="content_edit_folder" js="0">Edit Folder</word>
<word key="content_add_folder" js="0">Add Folder</word>
<word key="content_add_page" js="0">Add Page</word>
@@ -267,37 +280,24 @@
<word key="pages_different_gateway_load_error" js="0">Could not load Pages in this location. Have you uploaded the 'index.php' file?</word>
<word key="pages_different_gateway_load_error_rewrite" js="0"><![CDATA[Could not load Pages in this location. Have you uploaded the 'index.php' file and installed the .htaccess file? <a href='{external.devdocs-pages_different_root}' target='_blank'>More information</a>]]></word>
<word key="cms_root_page_url_rewrite_desc" js="0"><![CDATA[In order to support this you must <a href='{internal.app=cms&module=pages&controller=pages&do=htaccess}'><strong><u>download this file</u></strong></a>, rename it to '.htaccess' (with no file extension) and upload it to the same location as the special 'index.php' for Pages. If there is already a .htaccess file, add the contents of this one to the existing.<br>If you are not sure how to do this, contact technical support for assistance.]]></word>
<word key="menu_type" js="0">Type</word>
<word key="menu_type_desc" js="0">If you want to create a menu item that others can choose as a parent, choose 'Folder'.</word>
<word key="cms_tag_blocks" js="0">Blocks</word>
<word key="cms_tag_databases" js="0">Databases</word>
<word key="cms_tag_pages" js="0">Pages</word>
<word key="cms_error_page" js="0">Error Page</word>
<word key="cms_error_page_desc" js="0">A custom error page will be shown when the suite displays an error. Page builder pages are not suitable for error pages.</word>
<word key="cms_error_page_none" js="0">Do not use a custom error page</word>
<word key="cms_error_page_message" js="0">Error Message</word>
<word key="cms_error_page_code" js="0">Error Code</word>
<word key="cms_articles_homepage_form" js="0">Homepage Options</word>
<word key="menu_content_page" js="0">Page</word>
<word key="content_page_form_tab__menu" js="0">Menu</word>
<word key="page_add_to_menu" js="0">Add to front navigation menu</word>
<word key="menu_title_page_type" js="0">Title</word>
<word key="menu_title_page_inherit" js="0">Use the page name.</word>
<word key="menu_title_page_custom" js="0">I will enter a different title.</word>
<word key="menu_title_page" js="0">Title</word>
<word key="menu_title_page_desc" js="0">You may leave this blank to use the page's title.</word>
<word key="menu_content_url" js="0">URL</word>
<word key="menu_content_url_desc" js="0">This is a full URL including http:// or https:// where appropriate.</word>
<word key="menu_title_url" js="0">Title</word>
<word key="menu_parent_id" js="0">Parent</word>
<word key="cms_menu_form_type_page" js="0">Page</word>
<word key="cms_menu_form_type_url" js="0">URL</word>
<word key="cms_menu_form_type_separator" js="0">Separator</word>
<word key="cms_menu_form_type_folder" js="0">Folder</word>
<word key="cms_menu_adding" js="0">Add Menu Item</word>
<word key="cms_menu_edit" js="0">Editing %s</word>
<word key="menu_title_folder" js="0">Name</word>
<word key="cms_menu_perm_any" js="0">All groups</word>
<word key="menu_permission" js="0">Permission</word>
<word key="menu_permission_desc" js="0">Select which groups can see this menu item</word>
<word key="menu_permission_type" js="0">Permission Type</word>
<word key="cms_menu_form_perm_page" js="0">Honor page's can view permission</word>
<word key="cms_menu_form_perm_manual" js="0">Manually set permission</word>
<word key="content_page_form_tab__menu" js="0">Menu</word>
<word key="page_add_to_menu" js="0">Add to menu</word>
<word key="page_add_to_menu_desc" js="0">If you have not yet set one up then a new menu will be created replacing the default app menu item.</word>
<word key="cms_menu_information" js="0">Adding a new menu item without a parent will create a new top level tab in the suite navigation bar.</word>
<word key="cms_menu_no_item_perm" js="0">No view permissions</word>
<word key="cms_menu_add_child" js="0">Create Child</word>
<word key="cms_menu" js="0">Menu</word>
<word key="folder" js="0">Add Folder</word>
<word key="folder_add_child" js="0">Add Folder</word>
<word key="menu_parent" js="0">Parent</word>
<word key="field_title" js="0">Title</word>
<word key="field_description" js="0">Description</word>
<word key="field_type" js="0">Type</word>
@@ -390,6 +390,7 @@
<word key="pfield_options" js="0">Settings</word>
<word key="field_display_none" js="0">No formatting</word>
<word key="pf_type_Youtube" js="0">YouTube</word>
<word key="pf_type_Relational" js="0">Database Relationship</word>
<word key="media_display_listing_method" js="0">In listing, show as</word>
<word key="media_display_display_method" js="0">In a record, display as</word>
<word key="media_display_as_player" js="0">Embedded Player</word>
@@ -401,6 +402,7 @@
<word key="field_placeholder_youtube" js="0">Youtube URL</word>
<word key="field_placeholder_spotify" js="0">Spotify URL</word>
<word key="field_placeholder_soundcloud" js="0">Soundcloud URL</word>
<word key="field_placeholder_relational" js="0">Start typing the title of a %s</word>
<word key="cms_upload_field_is_image" js="0">Upload images only</word>
<word key="cms_upload_field_is_not_image" js="0">Upload any files</word>
<word key="field_image_size" js="0">Max. image dimensions</word>
@@ -415,6 +417,13 @@
<word key="field_default_update_existing" js="0">Update existing records</word>
<word key="field_default_update_existing_desc" js="0">This will update existing records with the current default value to the new default value</word>
<word key="field_upload_is_multiple" js="0">Allow multiple uploads</word>
<word key="field_relational_db" js="0">Database</word>
<word key="cms_relational_field_no_dbs" js="0">There are no databases to select</word>
<word key="cms_relational_field_no_db_selected" js="0">You must select a database</word>
<word key="field_display_display_json_where" js="0">Display</word>
<word key="field_display_display_json_where_desc" js="0">This may not have any affect when using custom templates</word>
<word key="cms_field_display_top" js="0">Above the item content</word>
<word key="cms_field_display_bottom" js="0">Under the item content</word>
<word key="content_content_form_tab__config" js="0">Configuration</word>
<word key="content_cat_db_title" js="0">%s Categories</word>
<word key="content_cat_furl_not_unique" js="0">The FURL slug is not unique</word>
@@ -469,6 +478,7 @@
<word key="record_author_choice" js="0">Author</word>
<word key="record_author_choice_me" js="0">I am the author</word>
<word key="record_author_choice_notme" js="0">Choose a member</word>
<word key="record_author_choice_guest" js="0">Guest</word>
<word key="record_member_id" js="0">Author's Name</word>
<word key="content_database_record_tab_comments" js="0">Comments</word>
<word key="record_allow_comments" js="0">Allow comments</word>
@@ -644,6 +654,36 @@
<word key="database_record_image_desc" js="0">This adds an image upload field to the record form. The image is displayed within the record text area by default.</word>
<word key="cms_no_db_page_no_forum_link" js="0">These settings will have no affect until this database is added to a page.</word>
<word key="cms_database_no_forum_selected" js="0">You have post topic enabled but have not selected a forum.</word>
<word key="cms_database_promote" js="0">Promote from Forums</word>
<word key="cms_promote_enabled" js="0">Enable</word>
<word key="cms_promote_cat" js="0">Add to category</word>
<word key="cms_promote_groups" js="0">Available for</word>
<word key="menu__cms_pages_media" js="0">Media</word>
<word key="r__media" js="0">Media</word>
<word key="r__media_manage" js="0">View Media</word>
<word key="r__media_add" js="0">Add Media</word>
<word key="r__media_edit" js="0">Edit Media</word>
<word key="r__media_delete" js="0">Delete Media</word>
<word key="cms_add_media_folder" js="0">New Folder</word>
<word key="cms_add_media" js="0">Upload New Media</word>
<word key="cms_delete_selected_media" js="0">Delete Selected</word>
<word key="cms_search_media" js="0">Search media...</word>
<word key="media_folders" js="0">Folders</word>
<word key="media_file_overview" js="0">File Overview</word>
<word key="media_root_folder" js="0">Pages Media</word>
<word key="media_tag_title" js="0">Media Tag</word>
<word key="media_tag_desc" js="0">Insert this tag in your pages/templates to insert this media item.</word>
<word key="media_folder_name" js="0">Name</word>
<word key="media_folder_parent" js="0">Parent</word>
<word key="cms_media_preview" js="0">Preview</word>
<word key="cms_no_media" js="0">Could not locate that media item</word>
<word key="media_filename" js="0">Filename</word>
<word key="media_uploaded" js="0">Uploaded</word>
<word key="media_size" js="0">File Size</word>
<word key="media_dims" js="0">Dimensions</word>
<word key="media_parent" js="0">Parent</word>
<word key="cms_media_key" js="0"><![CDATA[View page &amp; template tag]]></word>
<word key="cms_key_view" js="0"><![CDATA[This key can be used in blocks, pages and templates to fetch the URL of this media item.<br>The current URL for this item is: %s.]]></word>
<word key="content_categories_title" js="0">Categories</word>
<word key="content_subcategories_title" js="0">Subcategories</word>
<word key="x_records" js="0">%d %s</word>
@@ -669,6 +709,7 @@
<word key="content_record_form_new_record" js="0">Create New %s</word>
<word key="content_record_comment_title" js="0">%s Comment</word>
<word key="content_record_comments_title" js="0">%s Comments</word>
<word key="content_record_review_title" js="0">%s Review</word>
<word key="content_record_reviews_title" js="0">%s Reviews</word>
<word key="record_type" js="0">Type</word>
<word key="content_all_records" js="0">All</word>
@@ -721,7 +762,7 @@
<word key="cms_next_unread_title" js="0">Next unread %s</word>
<word key="cms_record_field_changed" js="0"><![CDATA[Changed <strong>%s</strong> to <strong>%s</strong>]]></word>
<word key="content_record_form_auto_follow" js="0"></word>
<word key="cms_locked_can_comment" js="0">This is now closed for further comments</word>
<word key="cms_locked_can_comment" js="0">This %s is locked, but your permissions allow you to add new replies.</word>
<word key="cms_select_category" js="0">Select a category</word>
<word key="cms_create_menu_records_x" js="0">%s in %s</word>
<word key="record_display_field_change" js="0">Add a comment recording this change.</word>
@@ -729,6 +770,7 @@
<word key="record_no_revision_data" js="0">No changes recorded</word>
<word key="record_locked_cannot_comment" js="0">This is now closed for further comments</word>
<word key="cms_moderator_options" js="0">Moderator Options</word>
<word key="cms_db_in_use_by_page" js="0">Database '%s' is already used by page '%s'</word>
<word key="cms_rf_database" js="0">Database</word>
<word key="cms_rf_database_desc" js="0">This cannot be changed. If you want to create a feed from a different database, please create a new custom block.</word>
<word key="cms_rf_category" js="0">Categories</word>
@@ -757,7 +799,6 @@
<word key="cms_rf_sort_dir_asc" js="0">Ascending (0-9)</word>
<word key="block_RecordFeed" js="0">Record Feed</word>
<word key="block_RecordFeed_desc" js="0">Create a customizable feed of database records</word>
<word key="cms_rf_tags" js="0">With tags</word>
<word key="block_Editor" js="0">Plain HTML Editor</word>
<word key="block_Editor_desc" js="0">Adds entered text as HTML</word>
<word key="block_Wysiwyg" js="0">WYSIWYG Editor</word>
@@ -788,6 +829,7 @@
<word key="block_rss_import_number" js="0">Number of items to show</word>
<word key="block_rss_import_cache" js="0">Cache for</word>
<word key="block_rss_import_cache_suffix" js="0">minutes</word>
<word key="widget_feed_container_cms" js="0">Categories</word>
<word key="loc_cms_viewing_page" js="0">Viewing %s</word>
<word key="loc_cms_viewing_db_cat" js="0">Viewing %s category %s</word>
<word key="loc_cms_viewing_db_record" js="0">Viewing %s in category %s: %s</word>
@@ -801,10 +843,24 @@
<word key="acplogs__cms_added_database" js="0">Added Database: %s</word>
<word key="acplogs__cms_edited_database" js="0">Edited Database: %s</word>
<word key="acplogs__cms_deleted_database" js="0">Deleted Database: %s</word>
<word key="block_embed_options" js="0">External embed</word>
<word key="embed_message" js="0"><![CDATA[This feature allows you to embed this block on an external page that <strong>isn't</strong> part of your IPS Community Suite. For pages created within the IPS Community Suite, use the normal embedding method instead.]]></word>
<word key="embed_1_title" js="0">Emedding this block</word>
<word key="embed_1_desc" js="0">To embed this block, paste the following code in your page where you'd like it to display. You can optionally have the block automatically inherit some styles (font family, link color, etc.) from the page it appears on.</word>
<word key="embed_1_toggle" js="0">Inherit key styles from the parent page</word>
<word key="embed_2_title" js="0">Insert the loader</word>
<word key="embed_2_desc" js="0"><![CDATA[You'll also need to insert the loader into your page. You only need to do this <strong>once per page</strong>, even if you use many external blocks. It should be inserted either in your <code>&lt;head&gt;</code> tag, or just before the <code>&lt;/body&gt;</code> tag.]]></word>
<word key="view_this_cmsrecord" js="0">View the %s %s</word>
<word key="cms_download_db" js="1">Download Database</word>
<word key="cms_download_db_explain" js="1"><![CDATA[This will download a file with the database settings, templates, custom fields and categories which can be uploaded to another community.<br>Records are <em>not</em> included.]]></word>
<word key="index_as_categories" js="1">Show categories</word>
<word key="index_as_records" js="1">Show record list</word>
<word key="mediaNoneSelected" js="1">No media items selected</word>
<word key="mediaMultipleSelected" js="1">{# [1:media item selected][?:media items selected]}</word>
<word key="mediaEmptyFolder" js="1">There's no items in this folder yet</word>
<word key="mediaConfirmDelete" js="1">Are you sure you want to delete {!# [1:this file][?:# selected files]}?</word>
<word key="mediaErrorDeleting" js="1">There was an error deleting {!# [1:this file][?:these files]}</word>
<word key="mediaNoResults" js="1">No files match your search term</word>
<word key="mediaUploadedCount" js="1">{!# [1:A file was][?:# files were]} added to this folder</word>
</app>
</language>
+217 -134
View File
@@ -3170,140 +3170,6 @@
"collation": "utf8mb4_unicode_ci",
"engine": "InnoDB"
},
"cms_page_menu": {
"name": "cms_page_menu",
"columns": {
"menu_id": {
"allow_null": false,
"auto_increment": true,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 10,
"name": "menu_id",
"type": "INT",
"unsigned": false,
"values": [],
"zerofill": false
},
"menu_parent_id": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 10,
"name": "menu_parent_id",
"type": "INT",
"unsigned": true,
"values": [],
"zerofill": false
},
"menu_position": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 10,
"name": "menu_position",
"type": "INT",
"unsigned": false,
"values": [],
"zerofill": false
},
"menu_type": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 0,
"name": "menu_type",
"type": "SET",
"unsigned": false,
"values": [
"url",
"page",
"separator",
"folder"
],
"zerofill": false
},
"menu_content": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 0,
"name": "menu_content",
"type": "TEXT",
"unsigned": false,
"values": [],
"zerofill": false
},
"menu_title": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "",
"length": 255,
"name": "menu_title",
"type": "VARCHAR",
"unsigned": false,
"values": [],
"zerofill": false
},
"menu_permission": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 0,
"name": "menu_permission",
"type": "TEXT",
"unsigned": false,
"values": [],
"zerofill": false
},
"menu_attributes": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 0,
"name": "menu_attributes",
"type": "TEXT",
"unsigned": false,
"values": [],
"zerofill": false
}
},
"indexes": {
"PRIMARY": {
"type": "primary",
"name": "PRIMARY",
"length": [
null
],
"columns": [
"menu_id"
]
}
}
},
"cms_database_reviews": {
"name": "cms_database_reviews",
"columns": {
@@ -3584,5 +3450,222 @@
]
}
}
},
"cms_media": {
"name": "cms_media",
"columns": {
"media_id": {
"allow_null": false,
"auto_increment": true,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 10,
"name": "media_id",
"type": "INT",
"unsigned": false,
"values": [],
"zerofill": false
},
"media_parent": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 10,
"name": "media_parent",
"type": "INT",
"unsigned": false,
"values": [],
"zerofill": false
},
"media_filename": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "",
"length": 255,
"name": "media_filename",
"type": "VARCHAR",
"unsigned": false,
"values": [],
"zerofill": false
},
"media_added": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 10,
"name": "media_added",
"type": "INT",
"unsigned": false,
"values": [],
"zerofill": false
},
"media_full_path": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 0,
"name": "media_full_path",
"type": "TEXT",
"unsigned": false,
"values": [],
"zerofill": false
},
"media_file_object": {
"name": "media_file_object",
"type": "TEXT",
"length": null,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
},
"media_filename_stored": {
"name": "media_filename_stored",
"type": "TEXT",
"length": null,
"decimals": null,
"values": [],
"allow_null": true,
"default": null,
"comment": "",
"unsigned": false,
"zerofill": false,
"auto_increment": false,
"binary": false
},
"media_is_image": {
"name": "media_is_image",
"type": "TINYINT",
"length": 1,
"decimals": null,
"values": [],
"allow_null": false,
"default": "0",
"comment": "",
"unsigned": true,
"zerofill": false,
"auto_increment": false,
"binary": false
}
},
"indexes": {
"PRIMARY": {
"type": "primary",
"name": "PRIMARY",
"length": [
null
],
"columns": [
"media_id"
]
}
},
"collation": "latin1_swedish_ci",
"engine": "InnoDB"
},
"cms_media_folders": {
"name": "cms_media_folders",
"columns": {
"media_folder_id": {
"allow_null": false,
"auto_increment": true,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 10,
"name": "media_folder_id",
"type": "INT",
"unsigned": false,
"values": [],
"zerofill": false
},
"media_folder_parent": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "0",
"length": 10,
"name": "media_folder_parent",
"type": "INT",
"unsigned": false,
"values": [],
"zerofill": false
},
"media_folder_name": {
"allow_null": false,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": "",
"length": 255,
"name": "media_folder_name",
"type": "VARCHAR",
"unsigned": false,
"values": [],
"zerofill": false
},
"media_folder_path": {
"allow_null": true,
"auto_increment": false,
"binary": false,
"comment": "",
"decimals": null,
"default": null,
"length": 0,
"name": "media_folder_path",
"type": "TEXT",
"unsigned": false,
"values": [],
"zerofill": false
}
},
"indexes": {
"PRIMARY": {
"type": "primary",
"name": "PRIMARY",
"length": [
null
],
"columns": [
"media_folder_id"
]
},
"media_folder_parent": {
"type": "key",
"name": "media_folder_parent",
"length": [
null
],
"columns": [
"media_folder_parent"
]
}
},
"collation": "latin1_swedish_ci",
"engine": "InnoDB",
"comment": ""
}
}
+16
View File
@@ -1,4 +1,20 @@
[
{
"key": "cms_error_page",
"default": "0"
},
{
"key": "cms_promote_cat",
"default": "0"
},
{
"key": "cms_promote_enabled",
"default": "0"
},
{
"key": "cms_promote_groups",
"default": "*"
},
{
"key": "cms_root_page_url",
"default": ""
+391 -52
View File
@@ -1,5 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<theme name="Default" author_name="Invision Power Services, Inc" author_url="http://www.invisionpower.com">
<template template_group="blocks" template_name="embedCode" template_data="$block, $embedKey" template_location="admin" template_app="cms"><![CDATA[
<div class="ipsMessage ipsMessage_info">
{lang="embed_message"}
</div>
<div data-controller='cms.admin.pages.embed'>
<div class='ipsPhotoPanel ipsPhotoPanel_mini ipsSpacer_top ipsSpacer_double'>
<span class='ipsPos_left ipsBadge ipsBadge_large ipsBadge_icon ipsBadge_positive'>1</span>
<div>
<h2 class='ipsType_sectionHead'>{lang="embed_1_title"}</h2>
<p>{lang="embed_1_desc"}</p>
<div class='ipsAreaBackground ipsPad'>
<input type='checkbox' id='elEmbedInherit' checked> <span class='ipsType_medium'>{lang="embed_1_toggle"}</span>
<textarea rows='2' spellcheck='false' class='ipsType_monospace ipsSpacer_top ipsSpacer_half' data-role='blockCode'>&lt;div id='block_{$embedKey}' data-blockID='{$block->key}' class='ipsExternalWidget' data-inheritStyle='true'&gt;&lt;/div&gt;</textarea>
</div>
</div>
</div>
<hr class='ipsHr'>
<div class='ipsPhotoPanel ipsPhotoPanel_mini'>
<span class='ipsPos_left ipsBadge ipsBadge_large ipsBadge_icon ipsBadge_positive'>2</span>
<div>
<h2 class='ipsType_sectionHead'>{lang="embed_2_title"}</h2>
<p>{lang="embed_2_desc"}</p>
<div class='ipsAreaBackground ipsPad'>
<textarea rows='2' spellcheck='false' class='ipsType_monospace'>&lt;script type='text/javascript' src='{url="applications/cms/interface/external/external.js" base="none"}' id='ipsWidgetLoader'&gt;&lt;/script&gt;</textarea>
</div>
</div>
</div>
</div>]]></template>
<template template_group="blocks" template_name="pluginSelector" template_data="$plugins, $id, $action, $elements, $hiddenValues, $actionButtons, $uploadField, $formClass='', $attributes=array(), $sidebar=''" template_location="admin" template_app="cms"><![CDATA[<div class='acpBlock'>
<form accept-charset='utf-8' action="{$action}" method="post">
<input type="hidden" name="{$id}_submitted" value="1">
@@ -83,6 +116,9 @@
<a class="ipsPos_right ipsBadge ipsBadge_style1" href="{$page->url()}" target="_blank">{lang="cms_db_used_on_page" sprintf="$page->_title"}</a>
{{endif}}
<p class='ipsType_light'>{$database->_description}</p>]]></template>
<template template_group="global" template_name="basicRelationship" template_data="$items" template_location="front" template_app="cms"><![CDATA[{{foreach $items as $id => $item}}
<a href="{$item->url()}">{$item->_title}</a>
{{endforeach}}]]></template>
<template template_group="global" template_name="commentTableHeader" template_data="$comment, $record" template_location="front" template_app="cms"><![CDATA[{{$iposted = $record->container()->contentPostedIn();}}
{{$idField = $record::$databaseColumnId;}}
<div>
@@ -102,27 +138,6 @@
{{endif}}
</h3>
<p class='ipsType_normal ipsType_light ipsType_blendLinks ipsType_reset'>{lang="in"} <a href='{$record->container()->url()}'>{$record->container()->_title}</a></p>
</div>]]></template>
<template template_group="global" template_name="snippet" template_data="$activity, $type='activity'" template_location="front" template_app="cms"><![CDATA[<div class='cSearchActivity_info ipsContained'>
{{if in_array( 'IPS\cms\Records', class_parents( $activity ) )}}
{{if $type != 'search'}}<a href='{$activity->url()}' class='ipsType_normal ipsType_break'>{$activity->mapped('title')}</a>{{endif}}
<div class='ipsType_medium ipsType_richText ipsContained {{if $type != 'search'}}ipsSpacer_both{{else}}ipsSpacer_bottom{{endif}} ipsSpacer_half' data-ipsTruncate data-ipsTruncate-size='3 lines' data-ipsTruncate-type='remove'>
{$activity->truncated()|raw}
</div>
<ul class='ipsList_inline ipsType_light'>
<li>{lang="replies_number" pluralize="$activity->mapped('num_comments')"}</li>
<li>{lang="num_views_with_number" pluralize="$activity->mapped('views')"}</li>
</ul>
{{else}}
<div class='ipsType_medium ipsType_richText ipsContained ipsSpacer_bottom ipsSpacer_half' data-ipsTruncate data-ipsTruncate-size='3 lines' data-ipsTruncate-type='remove'>
{$activity->truncated()|raw}
</div>
{{if $type != 'search' and $activity instanceof \IPS\Content\Reputation and settings.reputation_enabled}}
<ul class='ipsList_inline ipsType_light'>
<li>{template="reputationMini" group="global" app="core" params="$activity, '', NULL, TRUE"}</li>
</ul>
{{endif}}
{{endif}}
</div>]]></template>
<template template_group="global" template_name="uploadDisplay" template_data="$file, $record" template_location="front" template_app="cms"><![CDATA[{{if $file->isImage()}}
<img src="$file->url" class="ipsImage" data-ipsLightbox>
@@ -133,6 +148,131 @@
<a href="{$file->url}">{$file->originalFilename}</a>
{{endif}}
{{endif}}]]></template>
<template template_group="media" template_name="fileListing" template_data="$url, $item" template_location="admin" template_app="cms"><![CDATA[
{{if $item instanceof \IPS\cms\Media}}
<li class='ipsGrid_span4' data-role='mediaItem' data-fileid='{$item->id}' data-uploaded='{datetime="$item->added" dateonly="true"}' data-path='{$item->full_path}' data-filename='{$item->filename}' data-url='{$item->url()}' {{if $item->is_image}}data-isImage{{endif}}>
<div class='cMedia_item {{if $item->is_image}}cMedia_itemImage{{endif}}'>
<div class='ipsAreaBackground_light'>
{{if $item->is_image}}
<img src='{$item->url()}'>
{{else}}
<div class='ipsNoThumb'></div>
{{endif}}
</div>
<p class='cMedia_filename ipsType_reset ipsTruncate ipsTruncate_line'>{$item->filename}</p>
</div>
</li>
{{endif}}]]></template>
<template template_group="media" template_name="folderRow" template_data="$url, $row" template_location="admin" template_app="cms"><![CDATA[
{{if !( $row instanceof \IPS\cms\Media )}}
<li class='ipsTreeList_inactiveBranch' data-role="mediaFolder" data-folderID='{$row->id}'>
<a href='{$url->setQueryString( array( 'root' => $row->id ) )}'>{$row->name}</a>
<ul></ul>
</li>
{{endif}}]]></template>
<template template_group="media" template_name="media" template_data="$tree" template_location="admin" template_app="cms"><![CDATA[
{{$rootButtons = call_user_func( $tree->getRootButtons );}}
<div data-controller='cms.admin.media.main' class='cMedia_manager'>
<div class='acpBlock_title acpBlock_titleDark ipsAreaBackground_dark ipsPad'>
<div class='ipsColumns ipsColumns_collapsePhone'>
<div class='ipsColumn ipsColumn_wide'>
{{if $rootButtons['add_folder']}}
<a href='{$rootButtons['add_folder']['link']}' data-ipsDialog data-ipsDialog-title='{lang="cms_add_media_folder"}' class='ipsButton ipsButton_light ipsButton_small' data-role='folderButton'><i class='fa fa-plus'></i> {lang="cms_add_media_folder"}</a>
{{endif}}
</div>
<div class='ipsColumn ipsColumn_fluid'>
<ul class='ipsToolList ipsToolList_horizontal'>
{{if $rootButtons['add_page']}}
<li class='ipsPos_left'><a href='{url="app=cms&module=pages&controller=media&do=upload"}' data-ipsDialog data-ipsDialog-forceReload data-ipsDialog-remoteSubmit data-ipsDialog-title='{lang="cms_add_media"}' class='ipsButton ipsButton_normal ipsButton_small ipsButton_fullWidth' data-role='uploadButton'><i class='fa fa-cloud-upload'></i> &nbsp;{lang="cms_add_media"}</a></li>
{{endif}}
<li class='ipsPos_left ipsHide' data-action='deleteSelected'><a href='#' class='ipsButton ipsButton_negative ipsButton_small ipsButton_fullWidth'><i class='fa fa-times'></i> {lang="cms_delete_selected_media"}</a></li>
<li class='ipsResponsive_showPhone ipsResponsive_block'><hr class='ipsHr'></li>
<li class='ipsPos_right'>
<input type='search' class='' data-role='mediaSearch' id='elMedia_searchField' placeholder='{lang="cms_search_media"}'>
</li>
</ul>
</div>
</div>
</div>
<div class='ipsAreaBackground ipsPad'>
<div class='ipsColumns ipsColumns_collapsePhone'>
<div class='ipsColumn ipsColumn_wide'>
<div class="ipsTabs ipsTabs_stretch ipsClearfix acpFormTabBar" id="elMedia_sidebarTabs" data-ipsTabBar data-ipsTabBar-contentarea="#elMedia_sidebar" data-ipstabbar-updateurl="false">
<a href="#elMedia_sidebarTabs" data-action="expandTabs"><i class="fa fa-caret-down"></i></a>
<ul role='tablist'>
<li>
<a href="#" class="ipsTabs_item ipsTabs_activeItem" data-type="templates" id="elTab_folders" aria-selected="true">{lang="media_folders"}</a>
</li>
<li>
<a href="#" class="ipsTabs_item ipsTabs_itemDisabled" id='elTab_overview' data-type="css">{lang="media_file_overview"}</a>
</li>
</ul>
</div>
<div id='elMedia_sidebar' class='ipsAreaBackground_reset ipsScrollbar'>
<div id='ipsTabs_elMedia_sidebarTabs_elTab_folders_panel' class='ipsTabs_panel ipsPad'>
{{$roots = call_user_func( $tree->getRoots );}}
<ul class='ipsTreeList' data-role='folderList'>
<li class='ipsTreeList_activeBranch ipsTreeList_activeNode' data-role="mediaFolder" data-folderID='0' data-loaded='true'>
<a href='{$tree->url->setQueryString( array('root' => 0 ) )}'>{lang="media_root_folder"}</a>
<ul>
{{foreach $roots as $id => $row}}
{template="folderRow" group="media" app="cms" params="$tree->url, $row"}
{{endforeach}}
</ul>
</li>
</ul>
</div>
<div id='ipsTabs_elMedia_sidebarTabs_elTab_overview_panel' class='ipsTabs_panel ipsPad' data-role='mediaSidebar'>
<div data-role='itemInformation'>
<div class='ipsAreaBackground_light cMedia_preview ipsType_center' data-role='itemPreview'></div>
<div class='ipsSpacer_top'>
<strong class='ipsType_minorHeading'>{lang="media_tag_title"}</strong>
<input type='text' class='ipsField_fullWidth' value='' data-role='itemTag'>
<p class='ipsType_small ipsType_light'>{lang="media_tag_desc"}</p>
</div>
<hr class='ipsHr'>
<ul class='ipsList_reset ipsSpacer_top'>
<li class='ipsSpacer_bottom ipsSpacer_half'>
<h3 class='ipsType_minorHeading'>{lang="media_filename"}</h3>
<p class='ipsType_reset ipsType_medium' data-role='itemFilename'></p>
</li>
<li class='ipsSpacer_bottom ipsSpacer_half'>
<h3 class='ipsType_minorHeading'>{lang="media_uploaded"}</h3>
<p class='ipsType_reset ipsType_medium' data-role='itemUploaded'></p>
</li>
<li class='ipsSpacer_bottom ipsSpacer_half'>
<h3 class='ipsType_minorHeading'>{lang="media_size"}</h3>
<p class='ipsType_reset ipsType_medium' data-role='itemFilesize'></p>
</li>
<li class='ipsSpacer_bottom ipsSpacer_half' data-role='itemDimensionsRow'>
<h3 class='ipsType_minorHeading'>{lang="media_dims"}</h3>
<p class='ipsType_reset ipsType_medium' data-role='itemDimensions'></p>
</li>
</ul>
</div>
<div data-role='multipleItems'>
<div class='ipsPad ipsType_large ipsType_light ipsType_center ipsSpacer_top ipsSpacer_double' data-role='multipleItemsMessage'></div>
</div>
</div>
</div>
</div>
<div class='ipsColumn ipsColumn_fluid'>
<div class='ipsPad ipsAreaBackground_reset ipsScrollbar' data-role="fileListing" id='elMedia_fileList' data-showing='root'>
<ul class='ipsGrid' data-ipsGrid data-ipsGrid-minItemSize='100' data-ipsGrid-maxItemSize='200'>
{{foreach $roots as $id => $data}}
{template="fileListing" group="media" app="cms" params="$tree->url, $data"}
{{endforeach}}
</ul>
</div>
<div class='ipsPad ipsAreaBackground_reset ipsScrollbar ipsHide' data-role="searchResults" id='elMedia_searchResults'></div>
</div>
</div>
</div>
</div>]]></template>
<template template_group="pages" template_name="globalWrap" template_data="$navigation, $content, $page" template_location="front" template_app="cms"><![CDATA[<div id="elCmsPageWrap" data-pageid="{$page->id}">
{$content|raw}
</div>]]></template>
@@ -156,7 +296,8 @@
<div class='ipsPad'>
{$form|raw}
</div>]]></template>
<template template_group="records" template_name="commentTemplate" template_data="$id, $action, $elements, $hiddenValues, $actionButtons, $uploadField, $class=''" template_location="front" template_app="cms"><![CDATA[<form accept-charset='utf-8' class="ipsForm {$class}" action="{$action}" method="post" {{if $uploadField}}enctype="multipart/form-data"{{endif}}>
<template template_group="records" template_name="commentTemplate" template_data="$id, $action, $elements, $hiddenValues, $actionButtons, $uploadField, $class=''" template_location="front" template_app="cms"><![CDATA[{{$minimized = false;}}
<form accept-charset='utf-8' class="ipsForm {$class}" action="{$action}" method="post" {{if $uploadField}}enctype="multipart/form-data"{{endif}}>
<input type="hidden" name="{$id}_submitted" value="1">
{{foreach $hiddenValues as $k => $v}}
<input type="hidden" name="{$k}" value="{$v}">
@@ -185,6 +326,9 @@
{{foreach $elements as $collection}}
{{foreach $collection as $input}}
{{if $input instanceof \IPS\Helpers\Form\Editor}}
{{if $input->options['minimize'] !== NULL}}
{{$minimized = true;}}
{{endif}}
{$input->html( TRUE )|raw}
{{if $input->error}}
<br>
@@ -193,7 +337,7 @@
{{endif}}
{{endforeach}}
{{endforeach}}
<ul class='ipsToolList ipsToolList_horizontal ipsClear ipsClearfix' data-ipsEditor-toolList>
<ul class='ipsToolList ipsToolList_horizontal ipsClear ipsClearfix {{if $minimized}}ipsJS_hide{{endif}}' data-ipsEditor-toolList>
{{foreach $elements as $collection}}
{{foreach $collection as $input}}
{{if !($input instanceof \IPS\Helpers\Form\Editor) && $input->name != 'guest_name' and ! mb_stristr( $input->name, 'content_field_' )}}
@@ -224,11 +368,10 @@
<button data-ipsCancel class="ipsHide ipsButton ipsButton_veryVerySmall">{lang="cancel"}</button>
</div>]]></template>
<template template_group="records" template_name="fieldBadge" template_data="$label, $value, $classes" template_location="global" template_app="cms"><![CDATA[<span class='ipsBadge {$classes}'>{$label}: {$value|raw}</span>]]></template>
<template template_group="records" template_name="fieldDefault" template_data="$label, $value" template_location="global" template_app="cms"><![CDATA[<span class='ipsType_reset ipsType_light'>{$label}: {$value|raw}</span>]]></template>
<template template_group="records" template_name="fieldDefault" template_data="$label, $value" template_location="global" template_app="cms"><![CDATA[<div class='ipsType_reset ipsType_light'><strong>{$label}:</strong> {$value|raw}</div>]]></template>
<template template_group="records" template_name="soundcloud" template_data="$url, $params" template_location="global" template_app="cms"><![CDATA[<iframe {{foreach $params as $k => $v }}{$k}="{$v}" {{endforeach}} scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url={$url}&color=ff5500"></iframe>]]></template>
<template template_group="records" template_name="spotify" template_data="$url, $params" template_location="global" template_app="cms"><![CDATA[<iframe src="https://embed.spotify.com/?uri={$url}" {{foreach $params as $k => $v }}{$k}="{$v}" {{endforeach}} frameborder="0" allowtransparency="true"></iframe>]]></template>
<template template_group="records" template_name="title" template_data="$row, $title" template_location="admin" template_app="cms"><![CDATA[{$title}
{{if $row['record_future_date'] or $row['record_approved'] === -1 or $row['record_approved'] === 0 or $row['record_pinned'] === 1 or $row['record_featured'] === 1}}
<template template_group="records" template_name="title" template_data="$row, $title" template_location="admin" template_app="cms"><![CDATA[{{if $row['record_future_date'] or $row['record_approved'] === -1 or $row['record_approved'] === 0 or $row['record_pinned'] === 1 or $row['record_featured'] === 1}}
<span class='ipsPos_right'>
{{if $row['record_future_date']}}
{{$time = \IPS\DateTime::ts( $row['record_publish_date'] );}}
@@ -248,7 +391,7 @@
{{endif}}
</span>
{{endif}}
]]></template>
{$title}]]></template>
<template template_group="records" template_name="youtube" template_data="$url, $params" template_location="global" template_app="cms"><![CDATA[<div class='ipsEmbeddedVideo {{if \IPS\Settings::i()->max_video_width > 0}}ipsEmbeddedVideo_limited{{endif}}' contenteditable="false"><div><iframe id="ytplayer" type="text/html" {{foreach $params as $k => $v }}{$k}="{$v}" {{endforeach}} src="$url" frameborder="0"></iframe></div></div>]]></template>
<template template_group="revisions" template_name="rows" template_data="$table, $headers, $rows" template_location="front" template_app="cms"><![CDATA[{{foreach $rows as $row}}
<article class='ipsComment ipsComment_parent ipsClearfix ipsClear'>
@@ -569,11 +712,13 @@
<li class='ipsMenu_item'><a role='menuitem' href='{url="app=cms&module=pages&controller=templates&do=addTemplate&type=js"}' data-ipsDialog data-ipsDialog-forceReload data-ipsDialog-title='{lang="content_template_add_template_js_title""}'>{lang="content_template_add_template_js"}</a></li>
</ul>
<div class='ipsAreaBackground_reset'>
<ul class='ipsTabs ipsClearfix' id='elTemplateEditor_typeTabs' data-ipsTabBar data-ipsTabBar-contentArea='#elTemplateEditor_fileList' data-ipsTabBar-updateURL='false'>
<li><a href='{url="app=cms&module=pages&controller=templates&do=manage&t_type=templates"}' class='ipsTabs_item {{if $current->type == 'templates'}}ipsTabs_activeItem{{endif}}' data-tabURL='{url="app=cms&module=pages&controller=ajax&do=loadMenu&t_type=templates"}' data-type='templates'>{lang="theme_html"}</a></li>
<li><a href='{url="app=cms&module=pages&controller=templates&do=manage&t_type=css"}' class='ipsTabs_item {{if $current->type == 'css'}}ipsTabs_activeItem{{endif}}' data-tabURL='{url="app=cms&module=pages&controller=ajax&do=loadMenu&t_type=css"}' data-type='css'>{lang="theme_css"}</a></li>
<li><a href='{url="app=cms&module=pages&controller=templates&do=manage&t_type=js"}' class='ipsTabs_item {{if $current->type == 'js'}}ipsTabs_activeItem{{endif}}' data-tabURL='{url="app=cms&module=pages&controller=ajax&do=loadMenu&t_type=js"}' data-type='css'>{lang="theme_js"}</a></li>
</ul>
<div class='ipsTabs ipsClearfix ipsTabs_stretch acpFormTabBar' id='elTemplateEditor_typeTabs' data-ipsTabBar data-ipsTabBar-contentArea='#elTemplateEditor_fileList' data-ipsTabBar-updateURL='false'>
<ul role="tablist">
<li><a href='{url="app=cms&module=pages&controller=templates&do=manage&t_type=templates"}' class='ipsTabs_item ipsType_center {{if $current->type == 'templates'}}ipsTabs_activeItem{{endif}}' data-tabURL='{url="app=cms&module=pages&controller=ajax&do=loadMenu&t_type=templates"}' data-type='templates'>{lang="theme_html"}</a></li>
<li><a href='{url="app=cms&module=pages&controller=templates&do=manage&t_type=css"}' class='ipsTabs_item ipsType_center {{if $current->type == 'css'}}ipsTabs_activeItem{{endif}}' data-tabURL='{url="app=cms&module=pages&controller=ajax&do=loadMenu&t_type=css"}' data-type='css'>{lang="theme_css"}</a></li>
<li><a href='{url="app=cms&module=pages&controller=templates&do=manage&t_type=js"}' class='ipsTabs_item ipsType_center {{if $current->type == 'js'}}ipsTabs_activeItem{{endif}}' data-tabURL='{url="app=cms&module=pages&controller=ajax&do=loadMenu&t_type=js"}' data-type='css'>{lang="theme_js"}</a></li>
</ul>
</div>
<section id='elTemplateEditor_fileList'>
{template="menu" params="$templates, $current, $request" app="cms" location="admin" group="templates"}
</section>
@@ -597,7 +742,7 @@
<br>
<div id='elTemplateEditor_outerPanelWrap'>
<div id='elTemplateEditor_panelWrap'>
<ul id='elTemplateEditor_tabbar' class='ipsTabs ipsClearfix' data-ipsTabBar data-ipsTabBar-contentArea='#elTemplateEditor_panels'>
<ul id='elTemplateEditor_tabbar' class='ipsTabs ipsClearfix acpFormTabBar' data-ipsTabBar data-ipsTabBar-contentArea='#elTemplateEditor_panels'>
<li data-fileid='{$current->key}' data-type="{$current->type}" data-location='{$current->location}' data-group="{$current->group}">
<a href='#' class='ipsTabs_item' id='tab_{$current->key}'>{$current->title} <span data-action='closeTab'><i class='fa fa-times'></i></span></a>
</li>
@@ -661,7 +806,6 @@
<template template_group="widgets" template_name="Categories" template_data="$url" template_location="front" template_app="cms"><![CDATA[{{$catClass = '\IPS\cms\Categories' . \IPS\cms\Databases\Dispatcher::i()->databaseId;}}
{{$categories = $catClass::roots();}}
{{if !empty( $categories )}}
<div class='ipsBox'>
<h3 class='ipsWidget_title ipsType_reset'>{lang="categories"}</h3>
<div class='ipsSideMenu ipsAreaBackground_reset ipsPad_half'>
<ul class='ipsSideMenu_list'>
@@ -689,7 +833,6 @@
<a href='{$url->setQueryString('show','categories')}' class=''>{lang="cms_show_categories"} &nbsp;<i class='fa fa-caret-right'></i></a>
</p>
</div>
</div>
{{endif}}]]></template>
<template template_group="widgets" template_name="Database" template_data="$database" template_location="front" template_app="cms"><![CDATA[{database="$database->id" title="$database->title"}]]></template>
<template template_group="widgets" template_name="DatabaseFilters" template_data="$database, $category, $form, $orientation='vertical'" template_location="front" template_app="cms"><![CDATA[<h3 class='ipsWidget_title ipsType_reset'>{lang="block_DatabaseFilters_title" sprintf="$category->_title"}</h3>
@@ -702,8 +845,8 @@
{$content|raw}
</div>
]]></template>
<template template_group="widgets" template_name="RecordFeed" template_data="$database, $records, $orientation='vertical'" template_location="front" template_app="cms"><![CDATA[{{if !empty( $records ) }}
<h3 class='ipsWidget_title ipsType_reset'>{lang="block_latest_records" sprintf="$database->recordWord( 2, TRUE )"}</h3>
<template template_group="widgets" template_name="RecordFeed" template_data="$records, $title, $orientation='vertical'" template_location="front" template_app="cms"><![CDATA[{{if !empty( $records ) }}
<h3 class='ipsWidget_title ipsType_reset'>{$title}</h3>
{{if $orientation == 'vertical'}}
<div class='ipsPad_half ipsWidget_inner'>
<ul class='ipsDataList ipsDataList_reducedSpacing'>
@@ -781,24 +924,226 @@
padding-bottom: 0px;
}
.cCmsCategoryFeaturedEntry .cCmsRecord_image
{
max-height: 200px;
max-width: 200px;
.cCmsCategoryFeaturedEntry .cCmsRecord_image {
float: left;
margin-right: 6px;
margin-right: 15px;
margin-top: 4px;
border: 4px solid #e2e2e2;
}
.cCmsCategoryFeaturedEntry .cCmsRecord_image img {
max-width: 200px;
max-height: 200px;
max-width: 190px;
max-height: 190px;
}
.ipsDataItem_meta span.ipsBadge.ipsPos_right {
margin-left: 4px;
float: none;
}
/* 2 col */
.cmsCategory2col .ipsType_pageTitle {
font-size: 18px;
}
.cmsCategory2col .cmsInformation {
font-size: 12px;
}
.cmsCategory2col .cCmsRecord_image img {
max-height: 150px;
max-width: 150px;
}
.cmsCategory2col .ipsGrid_span6:nth-of-type(1) {
border-right: 1px solid #e2e2e2;
padding-right: 10px;
}
.cmsCategory2col .cCmsCategoryFeaturedEntry
{
border-bottom: 0px;
padding: 0px 0 30px 0;
}
.cmsCategory2col {
margin-top: 20px;
}
/* 3 col */
.cmsCategory3col .ipsType_pageTitle {
font-size: 16px;
}
.cmsCategory3col .cmsInformation {
font-size: 12px;
}
.cmsCategory3col .cCmsRecord_image img {
max-height: 100px;
max-width: 100px;
}
.cmsCategory3col .cCmsCategoryFeaturedEntry
{
border-bottom: 0px;
padding: 0px 0 30px 0;
}
.cmsCategory3col {
margin-top: 20px;
}
.cmsCategory3col .ipsGrid_span4:nth-of-type(1),
.cmsCategory3col .ipsGrid_span4:nth-of-type(2) {
border-right: 1px solid #e2e2e2;
padding-right: 10px;
}
/* 2 col featured image */
.cCmsCategoryFeaturedEntry.cms2ColImageFeature .cCmsRecord_image {
width: 100%;
max-width: none;
max-height: 250px;
overflow: hidden;
margin-bottom: 8px;
}
.cCmsCategoryFeaturedEntry.cms2ColImageFeature .cCmsRecord_image img {
width: 100%;
max-width: none;
max-height: none;
}
.cCmsCategoryFeaturedEntry.cms2ColImageFeature .ipsType_pageTitle {
font-size: 18px;
}
/* 3 col featured image */
.cCmsCategoryFeaturedEntry.cms3ColImageFeature .cCmsRecord_image {
width: 100%;
max-width: none;
max-height: 150px;
overflow: hidden;
margin-bottom: 8px;
}
.cCmsCategoryFeaturedEntry.cms3ColImageFeature .cCmsRecord_image img {
width: 100%;
max-width: none;
max-height: none;
}
.cCmsCategoryFeaturedEntry.cms3ColImageFeature .ipsType_pageTitle {
font-size: 14px;
}</css>
<css css_location="admin" css_app="cms" css_attributes="" css_path="media" css_name="media.css"><![CDATA[.cMedia_manager .ipsToolList li {
margin-top: 0 !important;
}
/* TABS */
#elMedia_sidebarTabs {
padding: 0;
}
#elMedia_sidebarTabs .ipsTabs_item {
border: 0 !important;
text-align: center;
margin: 0;
}
#elMedia_sidebarTabs .ipsTabs_activeItem {
background: #fff;
}
#elMedia_sidebar {
height: 550px;
overflow: auto;
}
#elMedia_fileList,
#elMedia_searchResults {
height: 587px;
overflow: auto;
}
#elMedia_searchField {
color: #333;
}
.cMedia_item {
padding: 15px 0 0;
text-align: center;
{prefix="transition" value="transform 0.1s ease-in-out"}
}
.cMedia_item:hover {
{prefix="transform" value="scale(1.05)"}
}
.cMedia_filename {
line-height: 22px;
border-radius: 22px;
padding: 0 10px;
}
.cMedia_item > div {
width: 100%;
height: 112px;
text-align: center;
margin: 0 auto;
padding: 5px;
margin-bottom: 7px;
line-height: 100px;
border: 1px solid transparent;
}
.cMedia_itemImage > div > img,
.cMedia_item > div > .ipsNoThumb {
max-width: 100%;
max-height: 100px;
}
.cMedia_itemSelected > div {
background: rgba( 84, 144, 192, 0.2 );
border: 1px solid rgba( 84, 144, 192, 0.5 );
box-shadow: 0px 0px 10px rgba( 84, 144, 192, 0.2 );
}
.cMedia_itemSelected .cMedia_filename {
background: #417ba3;
color: #fff;
}
.cMedia_itemDisabled,
.cMedia_treeDisabled {
opacity: 0.3;
pointer-events: none;
}
/* Sidebar */
.cMedia_preview img,
.cMedia_preview .ipsNoThumb {
max-width: 100%;
max-height: 200px;
margin: 0 auto;
}
.cMedia_preview img {
cursor: zoom-in;
}
/* ----- */
.ipsMedia_preview {
text-align: center;
}
.ipsMedia_preview img {
max-width: 100%;
}
.ipsMedia_key input[type=text] {
max-width: none;
}]]></css>
<css css_location="front" css_app="cms" css_attributes="" css_path="pages" css_name="page.css">/* ----- */
.ipsWidget.ipsWidget_horizontal[data-blockid^=&quot;app_cms&quot;]:not(.ipsBox) {
@@ -850,8 +1195,8 @@
float: left;
max-width: 300px;
max-height: 300px;
margin-right: 8px;
margin-bottom: 8px;
margin-right: 30px;
margin-bottom: 30px;
}
.cCmsRecord_image img {
@@ -878,7 +1223,6 @@ html[dir="rtl"] #elTemplateEditor_panelToolbar {
}
#elTemplateEditor .ipsTabs {
background: #d6d6d6;
padding: 0;
}
@@ -956,11 +1300,6 @@ html[dir="rtl"] #elTemplateEditor_panelToolbar {
margin-top: 15px;
}
#elTemplateEditor [data-role="fileList"] .ipsTabs_item {
width: 33.3%;
text-align: center;
}
.cTemplateList a {
padding: 5px 0;
display: block;
+14 -1
View File
@@ -92,5 +92,18 @@
"100042": "4.0.12",
"100043": "4.0.12.1",
"100044": "4.0.13",
"100045": "4.0.13.1"
"100045": "4.0.13.1",
"101000": "4.1.0 Beta 1",
"101001": "4.1.0 Beta 2",
"101002": "4.1.0 Beta 3",
"101003": "4.1.0 Beta 4",
"101004": "4.1.0 Beta 5",
"101005": "4.1.0 Beta 6",
"101006": "4.1.0 Beta 7",
"101007": "4.1.0 Beta 8",
"101008": "4.1.0 Beta 9",
"101009": "4.1.0 Beta 10",
"101010": "4.1.0",
"101011": "4.1.1",
"101012": "4.1.2"
}
+4 -2
View File
@@ -50,11 +50,13 @@
},
"RecordFeed": {
"class": "\\IPS\\Widget\\PermissionCache",
"restrict": false,
"restrict": [
"cms"
],
"default_area": "",
"allow_reuse": false,
"menu_style": "menu",
"embeddable": false
"embeddable": true
},
"Rss": {
"class": "\\IPS\\Widget\\StaticCache",
@@ -30,17 +30,21 @@ class _Records
public $classes = array();
/**
* Define classes here
* Constructor
*
* @return array
* @param \IPS\Member|NULL $member If checking access, the member to check for, or NULL to not check access
* @return void
*/
public function __construct()
public function __construct( \IPS\Member $member = NULL )
{
try
{
foreach ( \IPS\Db::i()->select( 'database_id', 'cms_databases', 'database_page_id>0' ) as $id )
{
$this->classes[] = 'IPS\cms\Records' . $id;
if ( !$member or call_user_func( array( 'IPS\cms\Databases', 'load' ), $id )->can( 'view', $member ) )
{
$this->classes[] = 'IPS\cms\Records' . $id;
}
}
}
catch ( \Exception $e ) {} // If you have not upgraded pages but it is installed, this throws an error
@@ -43,7 +43,7 @@ class _Cms
public function on( $data=NULL )
{
\IPS\cms\Theme\Advanced\Theme::export();
\IPS\cms\Media::exportDesignersModeMedia();
return TRUE;
}
@@ -55,6 +55,7 @@ class _Cms
public function off( $data=NULL )
{
\IPS\cms\Theme\Advanced\Theme::import();
\IPS\cms\Media::importDesignersModeMedia();
return TRUE;
}
@@ -58,8 +58,7 @@ class _BlockContent
{
try
{
$recordClass = '\IPS\cms\Records' . $id3;
return $recordClass::load( $id1 )->canView( $member );
return \IPS\cms\Blocks\Block::load( $id1 )->can( 'view' );
}
catch ( \OutOfRangeException $e )
{
@@ -80,8 +79,7 @@ class _BlockContent
{
try
{
$recordClass = '\IPS\cms\Records' . $id3;
return $recordClass::load( $id1 );
return \IPS\cms\Blocks\Block::load( $id1 );
}
catch ( \OutOfRangeException $e )
{
@@ -0,0 +1,119 @@
<?php
/**
* @brief File Storage Extension: Media
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @since 07 July 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms\extensions\core\FileStorage;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* File Storage Extension: CMS Media
*/
class _Media
{
/**
* Count stored files
*
* @return int
*/
public function count()
{
return \IPS\Db::i()->select( 'COUNT(*)', 'cms_media' )->first();
}
/**
* Move stored files
*
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
* @param int $storageConfiguration New storage configuration ID
* @param int|NULL $oldConfiguration Old storage configuration ID
* @throws \UnderflowException When file record doesn't exist. Indicating there are no more files to move
* @return void|int An offset integer to use on the next cycle, or nothing
*/
public function move( $offset, $storageConfiguration, $oldConfiguration=NULL )
{
$media = \IPS\Db::i()->select( '*', 'cms_media', array(), 'media_id', array( $offset, 1 ) )->first();
try
{
$file = \IPS\File::get( $oldConfiguration ?: 'cms_Media', $media['media_file_object'] )->move( $storageConfiguration );
if ( (string) $file != $media['media_file_object'] )
{
\IPS\Db::i()->update( 'cms_media', array( 'media_file_object' => (string) $file ), array( 'media_id=?', $media['media_id'] ) );
}
}
catch( \Exception $e )
{
/* Any issues are logged */
}
}
/**
* Fix all URLs
*
* @param int $offset This will be sent starting with 0, increasing to get all files stored by this extension
* @return void
*/
public function fixUrls( $offset )
{
$media = \IPS\Db::i()->select( '*', 'cms_media', array(), 'media_id', array( $offset, 1 ) )->first();
if ( $new = \IPS\File::repairUrl( $media['media_file_object'] ) )
{
\IPS\Db::i()->update( 'cms_media', array( 'media_file_object' => $new ), array( 'media_id=?', $media['media_id'] ) );
unset( \IPS\Data\Store::i()->emoticons );
}
}
/**
* Check if a file is valid
*
* @param \IPS\Http\Url $file The file to check
* @return bool
*/
public function isValidFile( $file )
{
try
{
$media = \IPS\Db::i()->select( '*', 'cms_media', array( 'media_file_object=?', (string) $file ) )->first();
return TRUE;
}
catch ( \UnderflowException $e )
{
return FALSE;
}
}
/**
* Delete all stored files
*
* @return void
*/
public function delete()
{
foreach( \IPS\Db::i()->select( '*', 'cms_media', 'media_file_object IS NOT NULL' ) as $item )
{
try
{
\IPS\File::get( 'cms_Media', $item['media_file_object'] )->delete();
}
catch( \Exception $e ){}
}
}
}
@@ -338,7 +338,7 @@ class _Records
{
try
{
$record = \IPS\Db::i()->select( '*', 'cms_custom_database_' . $databaseId, array( 'field_' . $fieldId .'=?', (string) $file ) )->first();
$record = \IPS\Db::i()->select( '*', 'cms_custom_database_' . $databaseId, 'field_' . $fieldId . " LIKE '%" . (string) $file . "%'" )->first();
return TRUE;
}
@@ -1,15 +1,5 @@
<?php
/**
* @brief Front Navigation Extension: Forums
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Board
* @since 08 Jan 2014
* @version SVN_VERSION_NUMBER
*/
/* This file has been removed in 4.1 but we do not want the 4.0 extension to load */
namespace IPS\cms\extensions\core\FrontNavigation;
/* To prevent PHP errors (extending class does not exist) revealing path */
@@ -20,143 +10,10 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
}
/**
* Front Navigation Extension: Content
* Front Navigation Extension: Pages
*/
class _Cms
class _Cms extends \IPS\core\FrontNavigation\FrontNavigationAbstract
{
/**
* @brief ID
*/
protected $id;
/**
* @brief Parent ID
*/
protected $parent;
/**
* Generate a number of classes for this extension
*
* @return array
*/
public static function generate()
{
/* Toggling mod_rewrite doesn't update cms_menu cache automatically */
if ( isset( \IPS\Data\Store::i()->cms_menu ) )
{
if ( ! isset( \IPS\Data\Store::i()->cms_menu['htaccess_mod_rewrite'] ) OR \IPS\Data\Store::i()->cms_menu['htaccess_mod_rewrite'] !== \IPS\Settings::i()->htaccess_mod_rewrite )
{
unset( \IPS\Data\Store::i()->cms_menu );
}
if ( ! isset( \IPS\Data\Store::i()->cms_menu['pages_is_default'] ) OR \IPS\Data\Store::i()->cms_menu['pages_is_default'] != \IPS\Application::load('cms')->default )
{
unset( \IPS\Data\Store::i()->cms_menu );
}
}
/* Make a tree if we don't have one */
if ( !isset( \IPS\Data\Store::i()->cms_menu ) )
{
$menu = array();
foreach( \IPS\Db::i()->select( '*', 'cms_page_menu', NULL, 'menu_position' ) as $row )
{
/* Construct the node */
$node = \IPS\cms\Pages\Menu::constructFromData( $row );
/* Can we see the parent? */
$permission = $node->permission;
if ( $node->type === 'page' and $node->permission === 'page' )
{
try
{
$perms = \IPS\cms\Pages\Page::load( $node->content )->permissions();
$permission = $perms['perm_view'];
}
catch( \OutOfRangeException $ex )
{
continue;
}
}
/* Work out the parent */
$parent = $node->parent_id ?: 0;
/* Add it */
$menu[ $parent ][ $node->_id ] = array(
'id' => $node->_id,
'type' => $node->type,
'content' => $node->content,
'title' => $node->title,
'url' => ( string ) $node->_url,
'permission' => $permission
);
}
try
{
$defaultUrl = \IPS\cms\Pages\Page::getDefaultPage()->url();
}
catch( \OutOfRangeException $ex )
{
$defaultUrl = \IPS\Http\Url::internal( 'app=cms&module=pages&controller=page', 'front', 'content' );
}
\IPS\Data\Store::i()->cms_menu = array(
'menu' => $menu,
'default' => (string) $defaultUrl,
'htaccess_mod_rewrite' => \IPS\Settings::i()->htaccess_mod_rewrite,
'pages_is_default' => \IPS\Application::load('cms')->default
);
}
$return = array();
if ( count( \IPS\Data\Store::i()->cms_menu['menu'] ) )
{
foreach( \IPS\Data\Store::i()->cms_menu['menu'][0] as $id => $data )
{
$return[] = new self( $id );
}
}
else
{
$return[] = new self(0);
}
return $return;
}
/**
* Constructor
*
* @param int $id The ID (0 for root)
* @param int $parent The Parent ID (0 for root)
* @return void
*/
public function __construct( $id = 0, $parent = 0 )
{
/* Set ID */
$this->id = $id;
$this->parent = $parent;
}
/**
* Can access?
*
* @return bool
*/
public function canView()
{
if ( $this->id )
{
return \IPS\Data\Store::i()->cms_menu['menu'][ $this->parent ][ $this->id ]['permission'] === '*' or \IPS\Member::loggedIn()->inGroup( explode( ',', \IPS\Data\Store::i()->cms_menu['menu'][ $this->parent ][ $this->id ]['permission'] ) );
}
else
{
return !\IPS\Application::load('cms')->hide_tab and \IPS\Member::loggedIn()->canAccessModule( \IPS\Application\Module::get( 'cms', 'pages' ) );
}
}
/**
* Get Title
*
@@ -164,121 +21,15 @@ class _Cms
*/
public function title()
{
if ( isset( \IPS\Data\Store::i()->cms_menu['menu'][ $this->parent ][ $this->id ] ) )
{
$item = \IPS\Data\Store::i()->cms_menu['menu'][ $this->parent ][ $this->id ];
return \IPS\Member::loggedIn()->language()->addToStack( $this->id ? ( ( ! $item['title'] and $item['type'] === 'page' ) ? 'cms_page_' . $item['content'] : 'cms_menu_title_' . $this->id ) : '__app_cms' );
}
return \IPS\Member::loggedIn()->language()->addToStack('__app_cms');
}
/**
* Get Root Link
* Get Link
*
* @return \IPS\Http\Url
*/
public function link()
{
if ( $this->id )
{
return \IPS\Data\Store::i()->cms_menu['menu'][ $this->parent ][ $this->id ]['url'] ?: '#';
}
else
{
return \IPS\Data\Store::i()->cms_menu['default'];
}
}
/**
* Get children
*
* @return array
*/
public function children()
{
if ( isset( \IPS\Data\Store::i()->cms_menu['menu'][ $this->id ] ) and count( \IPS\Data\Store::i()->cms_menu['menu'][ $this->id ] ) )
{
$return = array();
foreach ( \IPS\Data\Store::i()->cms_menu['menu'][ $this->id ] as $child )
{
$return[] = new Cms( $child['id'], $this->id );
}
return $return;
}
return array();
}
/**
* Is Active?
*
* @return bool
*/
public function active()
{
if ( \IPS\Dispatcher::i()->application->directory === 'cms' )
{
if ( ! count( \IPS\Data\Store::i()->cms_menu['menu'] ) )
{
return TRUE;
}
if ( \IPS\cms\Pages\Page::$currentPage )
{
/* A page... ? */
if ( \IPS\Data\Store::i()->cms_menu['menu'][ $this->parent ][ $this->id ]['type'] === 'page' AND \IPS\cms\Pages\Page::$currentPage->id == \IPS\Data\Store::i()->cms_menu['menu'][ $this->parent ][ $this->id ]['content'] )
{
return TRUE;
}
/* A folder that has the page inside? */
if ( \IPS\Data\Store::i()->cms_menu['menu'][ $this->parent ][ $this->id ]['type'] === 'folder' )
{
if ( isset( \IPS\Data\Store::i()->cms_menu['menu'][ $this->id ] ) )
{
foreach( \IPS\Data\Store::i()->cms_menu['menu'][ $this->id ] as $id => $data )
{
if ( $this->checkInsideFolderForCurrentPage( $this->id ) === TRUE )
{
return TRUE;
}
}
}
}
}
}
return FALSE;
}
/**
* Check recursively to see if the current page is in side the folder
*
* @param $parent
*
* @return bool
*/
protected function checkInsideFolderForCurrentPage( $parent )
{
if ( isset( \IPS\Data\Store::i()->cms_menu['menu'][ $parent ] ) )
{
foreach( \IPS\Data\Store::i()->cms_menu['menu'][ $parent ] as $id => $data )
{
if ( \IPS\cms\Pages\Page::$currentPage->id == $data['content'] )
{
return TRUE;
}
else
{
if ( $this->checkInsideFolderForCurrentPage( $id ) === TRUE )
{
return TRUE;
}
}
}
}
return FALSE;
}
}
@@ -0,0 +1,178 @@
<?php
/**
* @brief Front Navigation Extension: Pages
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Pages
* @since 01 Jul 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms\extensions\core\FrontNavigation;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Front Navigation Extension: Pages
*/
class _Pages extends \IPS\core\FrontNavigation\FrontNavigationAbstract
{
/**
* Get Type Title which will display in the AdminCP Menu Manager
*
* @return string
*/
public static function typeTitle()
{
return \IPS\Member::loggedIn()->language()->addToStack('menu_content_page');
}
/**
* Allow multiple instances?
*
* @return string
*/
public static function allowMultiple()
{
return TRUE;
}
/**
* Get configuration fields
*
* @param array $configuration The existing configuration, if editing an existing item
* @param int $id The ID number of the existing item, if editing
* @return array
*/
public static function configuration( $existingConfiguration, $id = NULL )
{
$pages = array();
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'cms_pages' ), 'IPS\cms\Pages\Page' ) as $page )
{
$pages[ $page->id ] = $page->full_path;
}
return array(
new \IPS\Helpers\Form\Select( 'menu_content_page', isset( $existingConfiguration['menu_content_page'] ) ? $existingConfiguration['menu_content_page'] : NULL, NULL, array( 'options' => $pages ), NULL, NULL, NULL, 'menu_content_page' ),
new \IPS\Helpers\Form\Radio( 'menu_title_page_type', isset( $existingConfiguration['menu_title_page'] ) ? $existingConfiguration['menu_title_page'] : 0, NULL, array( 'options' => array( 0 => 'menu_title_page_inherit', 1 => 'menu_title_page_custom' ), 'toggles' => array( 1 => array( 'menu_title_page' ) ) ), NULL, NULL, NULL, 'menu_title_page_type' ),
new \IPS\Helpers\Form\Translatable( 'menu_title_page', NULL, NULL, array( 'app' => 'cms', 'key' => $id ? "cms_menu_title_{$id}" : NULL ), NULL, NULL, NULL, 'menu_title_page' ),
);
}
/**
* Parse configuration fields
*
* @param array $configuration The values received from the form
* @return array
*/
public static function parseConfiguration( $configuration, $id )
{
if ( $configuration['menu_title_page_type'] )
{
\IPS\Lang::saveCustom( 'cms', "cms_menu_title_{$id}", $configuration['menu_title_page'] );
}
else
{
\IPS\Lang::deleteCustom( 'cms', "cms_menu_title_{$id}" );
}
unset( $configuration['menu_title_page'] );
return $configuration;
}
/**
* Can access?
*
* @return bool
*/
public function canView()
{
if ( $this->permissions )
{
if ( $this->permissions != '*' )
{
return \IPS\Member::loggedIn()->inGroup( explode( ',', $this->permissions ) );
}
return TRUE;
}
/* Inherit from page */
$store = \IPS\cms\Pages\Page::getPageUrlStore();
if ( isset( $store[ $this->configuration['menu_content_page'] ] ) )
{
if ( $store[ $this->configuration['menu_content_page'] ]['perm'] != '*' )
{
return \IPS\Member::loggedIn()->inGroup( explode( ',', $store[ $this->configuration['menu_content_page'] ]['perm'] ) );
}
return TRUE;
}
return FALSE;
}
/**
* Get Title
*
* @return string
*/
public function title()
{
if ( $this->configuration['menu_title_page_type'] )
{
return \IPS\Member::loggedIn()->language()->addToStack( "cms_menu_title_{$this->id}" );
}
else
{
return \IPS\Member::loggedIn()->language()->addToStack( "cms_page_{$this->configuration['menu_content_page']}" );
}
}
/**
* Get Link
*
* @return \IPS\Http\Url
*/
public function link()
{
$store = \IPS\cms\Pages\Page::getPageUrlStore();
if ( isset( $store[ $this->configuration['menu_content_page'] ] ) )
{
return $store[ $this->configuration['menu_content_page'] ]['url'];
}
/* Fall back here */
return \IPS\cms\Pages\Page::load( $this->configuration['menu_content_page'] )->url();
}
/**
* Is Active?
*
* @return bool
*/
public function active()
{
return ( \IPS\cms\Pages\Page::$currentPage and \IPS\cms\Pages\Page::$currentPage->id == $this->configuration['menu_content_page'] ) or parent::active();
}
/**
* Children
*
* @return array
*/
public function children()
{
return array();
}
}
@@ -50,11 +50,7 @@ class _Databases
foreach( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'field_type=?', 'Member' ) ) as $field )
{
$where = array(
'field_' . $field['field_id'] . '=? OR field_' . $field['field_id'] . ' LIKE ? OR ' . $field['field_id'] . ' LIKE ? OR ' . $field['field_id'] . ' LIKE ?',
$member2->member_id,
$member2->member_id . ',%',
'%,' . $member2->member_id . ',%',
'%,' . $member2->member_id
\IPS\Db::i()->findInSet( 'field_' . $field['field_id'], array( $member2->member_id ) )
);
foreach ( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $field['field_database_id'], $where ) as $record )
@@ -99,11 +95,7 @@ class _Databases
foreach( \IPS\Db::i()->select( '*', 'cms_database_fields', array( 'field_type=?', 'Member' ) ) as $field )
{
$where = array(
'field_' . $field['field_id'] . '=? OR field_' . $field['field_id'] . ' LIKE ? OR ' . $field['field_id'] . ' LIKE ? OR ' . $field['field_id'] . ' LIKE ?',
$member->member_id,
$member->member_id . ',%',
'%,' . $member->member_id . ',%',
'%,' . $member->member_id
\IPS\Db::i()->findInSet( 'field_' . $field['field_id'], array( $member->member_id ) )
);
foreach ( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $field['field_database_id'], $where ) as $record )
@@ -0,0 +1,65 @@
<?php
/**
* @brief Template Plugin - Pages: Media
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 07 July 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms\extensions\core\OutputPlugins;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Template Plugin - Content: Media
*/
class _Media
{
/**
* @brief Can be used when compiling CSS
*/
public static $canBeUsedInCss = TRUE;
/**
* Run the plug-in
*
* @param string $data The initial data from the tag
* @param array $options Array of options
* @return string Code to eval
*/
public static function runPlugin( $data, $options )
{
if ( is_numeric( $data ) )
{
try
{
$url = \IPS\cms\Media::load( $data )->url();
}
catch( \OutOfRangeException $ex )
{
$url = NULL;
}
}
else
{
try
{
$url = \IPS\cms\Media::load( $data, 'media_full_path' )->url();
}
catch( \OutOfRangeException $ex )
{
$url = NULL;
}
}
return "'" . (string) $url . "'";
}
}
@@ -119,7 +119,7 @@ class _Databases
{
$select = new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', $nodeClass::$databaseTable, array( '(' . \IPS\Db::i()->findInSet( 'perm_view', array( \IPS\Settings::i()->guest_group ) ) . ' OR ' . 'perm_view=? )', '*' ) )->join( 'core_permission_index', array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id={$nodeClass::$databaseTable}.{$nodeClass::$databasePrefix}{$nodeClass::$databaseColumnId}", $nodeClass::$permApp, $nodeClass::$permType ) ), $nodeClass );
}
else if ( $nodeClass::$ownerTypes !== NULL and is_subclass_of( $nodeClass, 'IPS\Node\Model', true ) )
else if ( $nodeClass::$ownerTypes !== NULL and is_subclass_of( $nodeClass, 'IPS\Node\Model' ) )
{
$select = $nodeClass::loadByOwner( new \IPS\Member );
}
+92
View File
@@ -0,0 +1,92 @@
//<?php
class cms_hook_Output extends _HOOK_CLASS_
{
/**
* Display Error Screen
*
* @param string $message language key for error message
* @param mixed $code Error code
* @param int $httpStatusCode HTTP Status Code
* @param string $adminMessage language key for error message to show to admins
* @param array $httpHeaders Additional HTTP Headers
* @param string $extra Additional information (such as API error)
* @return void
*/
public function error( $message, $code, $httpStatusCode=500, $adminMessage=NULL, $httpHeaders=array(), $extra=NULL )
{
if ( ! isset( \IPS\Settings::i()->cms_error_page ) or ! \IPS\Settings::i()->cms_error_page )
{
parent::error( $message, $code, $httpStatusCode, $adminMessage, $httpHeaders, $extra );
}
/* If we just logged out, we don't want to show a "no permission" error */
if ( isset( \IPS\Request::i()->_fromLogout ) )
{
$this->redirect( \IPS\Settings::i()->base_url );
}
/* If we're in an external script, just show a simple message */
if ( !\IPS\Dispatcher::hasInstance() )
{
\IPS\Session\Front::i();
$this->sendOutput( \IPS\Member::loggedIn()->language()->get( $message ), $httpStatusCode, 'text/html', $httpHeaders, FALSE );
return;
}
if ( \IPS\Dispatcher::i()->controllerLocation !== 'front' )
{
parent::error( $message, $code, $httpStatusCode, $adminMessage, $httpHeaders, $extra );
}
/* Work out the title */
$title = "{$httpStatusCode}_error_title";
$title = \IPS\Member::loggedIn()->language()->checkKeyExists( $title ) ? \IPS\Member::loggedIn()->language()->addToStack( $title ) : \IPS\Member::loggedIn()->language()->addToStack( 'error_title' );
/* Which message are we showing? */
if( \IPS\Member::loggedIn()->isAdmin() and $adminMessage )
{
$message = $adminMessage;
}
if ( \IPS\Member::loggedIn()->language()->checkKeyExists( $message ) )
{
$message = \IPS\Member::loggedIn()->language()->addToStack( $message );
}
/* Replace language stack keys with actual content */
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $message );
/* Log */
$level = intval( \substr( $code, 0, 1 ) );
if( !\IPS\Session::i()->userAgent->spider )
{
if( $code and \IPS\Settings::i()->error_log_level and $level >= \IPS\Settings::i()->error_log_level )
{
\IPS\Db::i()->insert( 'core_error_logs', array(
'log_member' => \IPS\Member::loggedIn()->member_id ?: 0,
'log_date' => time(),
'log_error' => $message,
'log_error_code' => $code,
'log_ip_address' => \IPS\Request::i()->ipAddress(),
'log_request_uri' => $_SERVER['REQUEST_URI'],
) );
}
if( \IPS\Settings::i()->error_notify_level and $level >= \IPS\Settings::i()->error_notify_level )
{
\IPS\Email::buildFromTemplate( 'core', 'error_log', array( $code, $message ) )->send( \IPS\Settings::i()->email_in );
}
}
/* If this is an AJAX request, send a JSON response */
if( \IPS\Request::i()->isAjax() )
{
$this->json( $message, $httpStatusCode );
}
/* Send output */
\IPS\cms\Pages\Page::errorPage( $title, $message, $code, $httpStatusCode, $httpHeaders );
}
}
+1 -1
View File
@@ -32,7 +32,7 @@ class cms_hook_Url extends _HOOK_CLASS_
{
if ( isset( $this->data['path'] ) and mb_strpos( $this->data['path'], 'index.php?' ) )
{
$query = ( isset( $this->data['query'] ) ? $this->data['query'] : '' );
$query = ( isset( $this->data['query'] ) ? ltrim( $this->data['query'], '/' ) : '' );
}
else
{
+39
View File
@@ -0,0 +1,39 @@
//<?php
class cms_hook_websiteUrl extends _HOOK_CLASS_
{
/* !Hook Data - DO NOT REMOVE */
public static function hookData() {
return array_merge_recursive( array (
'globalTemplate' =>
array (
0 =>
array (
'selector' => 'html > body > meta[itemprop=\'url\']',
'type' => 'replace',
'content' => '{{if \IPS\Settings::i()->cms_use_different_gateway AND \IPS\Settings::i()->cms_root_page_url}}
<meta itemprop="url" content="{setting="cms_root_page_url"}">
{{else}}
<meta itemprop="url" content="{setting="base_url"}">
{{endif}}',
),
),
), parent::hookData() );
}
/* End Hook Data */
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

+342
View File
@@ -0,0 +1,342 @@
/*
* IPS external widgets loader
*
* http://www.invisionpower.com
*/
( function () {
"use strict";
var _baseURL = '';
var _widgets = {};
var _scriptAttributes = {};
/**
* Initialization
*/
var initialize = function () {
// Get our script attributes
var thisScript = getOurScript();
_scriptAttributes = getAttributesFrom( thisScript );
// Set our base URL
_baseURL = _scriptAttributes.src.replace( 'external.js', 'external.php' );
// Main message handler
eventHandler.on( window, 'message', function (e) {
try {
var pmData = JSON.parse( e.data );
} catch (err) {
return;
}
if( typeof pmData.method == 'undefined' || typeof pmData.widgetID == 'undefined' || typeof pmData.blockID == 'undefined' ){
return;
}
// Ensure this is a valid frame
if( typeof _widgets[ pmData.widgetID ] == 'undefined' ){
return;
}
if( pmData.method && typeof messageEvents[ pmData.method ] != 'undefined' ){
messageEvents[ pmData.method ].call( this, pmData );
}
});
// We need to find the IPS widgets on the page
var widgets = document.getElementsByClassName('ipsExternalWidget');
if( !widgets.length ) {
utils.log("No widgets found.");
return;
}
for( var i = 0; i < widgets.length; i++ ){
createWidget( widgets[i] );
};
};
/**
* Handles events from the iframe
*
*/
var messageEvents = {
/**
* iframe tells us we're ready; if we need to send styles, do that now
*
* @param {object} data Data object
* @returns {void}
*/
iframeReady: function (data) {
var thisWidgetInfo = _widgets[ data.widgetID ];
utils.log( thisWidgetInfo );
// Do we need to send probed styles?
if( thisWidgetInfo.useStyles ){
_postMessage( data.widgetID, 'probedStyles', {
text: thisWidgetInfo['text'],
font: thisWidgetInfo['font'],
link: thisWidgetInfo['link']
});
}
},
/**
* iframe has sent a size; resize it to fit
*
* @param {object} data Data object
* @returns {void}
*/
iframeSize: function (data) {
var block = document.getElementById( 'ipsFrame_' + data.widgetID );
block.style.height = parseInt( data.size ) + 'px';
},
/**
* Link clicked inside iframe; open it in parent
*
* @param {object} data Data object
* @returns {void}
*/
goToLink: function (data) {
window.location = data.link;
}
};
/**
* Creates a widget in the page, replacing the element in the param
*
* @param {element} widget
* @returns {void}
*/
var createWidget = function (widget) {
var widgetAttributes = getAttributesFrom( widget );
// Make sure we have a block ID
if( typeof widgetAttributes.id == 'undefined' || typeof widgetAttributes['data-blockid'] == 'undefined' ){
utils.error("Widget class found but no block ID available.");
return;
}
var widgetID = widgetAttributes.id.replace( 'block_', '' );
var blockID = widgetAttributes['data-blockid'];
_widgets[ widgetID ] = {
blockID: blockID
};
// Create the iframe to replace this
var iframe;
iframe = document.createElement('iframe');
iframe.src = _baseURL + '?widgetid=' + widgetID + '&blockid=' + blockID;
iframe.id = 'ipsFrame_' + widgetID;
iframe.scrolling = 'no';
iframe.style.width = '100%';
iframe.style.border = '0';
iframe.style.opacity = '1';
// Do we need to probe for some styles
if( typeof widgetAttributes['data-inheritstyle'] != 'undefined' ){
var styles = _createStyleProbes( widget );
_widgets[ widgetID ]['useStyles'] = true;
_widgets[ widgetID ]['link'] = styles.link;
_widgets[ widgetID ]['text'] = styles.text;
_widgets[ widgetID ]['font'] = styles.font;
}
// Now insert the iframe
widget.parentElement.replaceChild( iframe, widget );
};
/**
* Create elements and probe for some key styles that we'll share with the iframes
*
* @returns {void}
*/
var _createStyleProbes = function (element) {
var styles = {};
//=====
// First, a simple link
var a = document.createElement('a');
utils.insertBefore( a, element );
styles['link'] = utils.getStyle( a, 'color' );
a.parentNode.removeChild( a );
//=====
// Next create a paragraph
var p = document.createElement('p');
utils.insertBefore( p, element );
styles['font'] = utils.getStyle( p, 'font-family' );
styles['text'] = utils.getStyle( p, 'color' );
p.parentNode.removeChild( p );
return styles;
};
/**
* Returns the attributes on the given element
*
* @param {element} element
* @returns {object} The attributes in key/value pairs
*/
var getAttributesFrom = function (element) {
if( typeof element == 'undefined' ){
return;
}
var attributes = {};
if( element.hasAttributes() ){
var _attr = element.attributes;
for( var i = 0; i < _attr.length; i++ ){
attributes[ _attr[ i ].name.toLowerCase() ] = _attr[ i ].value;
}
}
return attributes;
};
/**
* Finds and returns our script
*
* @param {element} element
* @returns {object} The attributes in key/value pairs
*/
var getOurScript = function () {
return document.getElementById('ipsWidgetLoader');
};
/**
* Posts a message to the iframes
*
* @param {number} [pageNo] Page number to load
* @returns {void}
*/
var _postMessage = function (iframeID, method, data) {
var iframe = document.getElementById( 'ipsFrame_' + iframeID );
iframe.contentWindow.postMessage( JSON.stringify( utils.extendObj( data || {}, {
method: method,
widgetID: iframeID
})), '*' );
};
var utils = {
/*
* Cross-browser 'dom ready' event handler to init the page
*/
/*! contentloaded.min.js - https://github.com/dperini/ContentLoaded - Author: Diego Perini - License: MIT */
contentLoaded: function (b,i) {
var j=false,k=true,a=b.document,l=a.documentElement,f=a.addEventListener,h=f?'addEventListener':'attachEvent',n=f?'removeEventListener':'detachEvent',g=f?'':'on',c=function(d){if(d.type=='readystatechange'&&a.readyState!='complete')return;(d.type=='load'?b:a)[n](g+d.type,c,false);if(!j&&(j=true))i.call(b,d.type||d)},m=function(){try{l.doScroll('left')}catch(e){setTimeout(m,50);return}c('poll')};if(a.readyState=='complete')i.call(b,'lazy');else{if(!f&&l.doScroll){try{k=!b.frameElement}catch(e){}if(k)m()}a[h](g+'DOMContentLoaded',c,false);a[h](g+'readystatechange',c,false);b[h](g+'load',c,false)}
},
/**
* Extend an object with another object
*
* @param {object} originalObj Original object
* @param {object} newObj New object
* @returns {void}
*/
extendObj: function (originalObj, newObj) {
for( var i in newObj ){
if( newObj.hasOwnProperty(i) ){
originalObj[i] = newObj[i];
}
}
return originalObj;
},
/**
* Log to console if supported
*
* @param {string} message Message to log
* @returns {void}
*/
log: function (message) {
if( window.console ){
console.log( message );
}
},
/**
* Error to console if supported
*
* @param {string} message Message to log
* @returns {void}
*/
error: function (message) {
if( window.console ){
console.error( message );
}
},
/**
* A simple method to insert an element before another element
*
* @param {element} elem The new element
* @param {element} existing The existing element, before which the new will be inserted
* @returns {void}
*/
insertBefore: function (elem, existing) {
existing.parentNode.insertBefore( elem, existing );
},
/**
* Returns a style property value for the given element and style
*
* @param {element} elem Element whose style is to be fetched
* @param {string} style Property to fetch
* @returns {mixed}
*/
getStyle: function (elem, style) {
return window.getComputedStyle( elem, null ).getPropertyValue( style );
}
};
/**
* Event handling
*
*/
// http://www.anujgakhar.com/2013/05/22/cross-browser-event-handling-in-javascript/
var eventHandler = {
on: function (el, ev, fn) {
if( window.addEventListener ){
el.addEventListener( ev, fn, false );
} else if( window.attachEvent ){
el.attachEvent( 'on' + ev, fn );
} else {
el[ 'on' + ev ] = fn;
}
},
off: function (el, ev, fn) {
if( window.removeEventListener ){
el.removeEventListener( ev, fn, false );
} else if( window.detachEvent ) {
el.detachEvent( 'on' + ev, fn );
} else {
elem[ 'on' + ev ] = null;
}
},
stop: function (ev) {
var e = ev || window.event;
e.cancelBubble = true;
if( e.stopPropagation ){
e.stopPropagation();
}
}
};
// Once the DOM is ready we'll initialize our widgets
utils.contentLoaded( window, function () {
initialize();
});
}() );
+22
View File
@@ -0,0 +1,22 @@
<?php
/**
* @brief Pages External Block Gateway
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 30 Jun 2015
* @version SVN_VERSION_NUMBER
*
*/
require_once str_replace( 'applications/cms/interface/external/external.php', '', str_replace( '\\', '/', __FILE__ ) ) . 'init.php';
\IPS\Dispatcher\Front::i();
$id = \IPS\Request::i()->blockid;
$k = \IPS\Request::i()->widgetid;
$block = \IPS\cms\Blocks\Block::display( $id );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_external.js', 'cms', 'front' ) );
\IPS\Output::i()->globalControllers[] = 'cms.front.external.communication';
\IPS\Output::i()->sendOutput( \IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->blankTemplate( $block ) ), 200, 'text/html' );
@@ -131,6 +131,16 @@ class _databases extends \IPS\Node\Controller
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_database_add') )
),
);
/*if ( \IPS\Application::appIsEnabled('forums') )
{
\IPS\Output::i()->sidebar['actions']['promote'] = array(
'title' => 'cms_database_promote',
'icon' => 'comments',
'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=promote' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_database_promote') )
);
}*/
$table->rowButtons = function( $row )
{
@@ -243,7 +253,7 @@ class _databases extends \IPS\Node\Controller
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( 'cms_database_add', $form, FALSE );
}
/**
/**
* Import from upload
*
* @return void
@@ -1055,7 +1065,45 @@ class _databases extends \IPS\Node\Controller
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core' )->block( 'delete', $form, FALSE );
}
/**
* Promote
*
* @return void
*/
protected function promote()
{
$form = new \IPS\Helpers\Form( 'form', 'save' );
$form->add( new \IPS\Helpers\Form\YesNo( 'cms_promote_enabled', \IPS\Settings::i()->cms_promote_enabled, FALSE, array( 'togglesOn' => array( 'cms_promote_cat', 'cms_promote_groups' ) ) ) );
$form->add( new \IPS\Helpers\Form\Node( 'cms_promote_cat', \IPS\Settings::i()->cms_promote_cat ? \IPS\Settings::i()->cms_promote_cat : 0, FALSE, array(
'class' => '\IPS\cms\Selector\Databases',
'subnodes' => true,
), NULL, NULL, NULL, 'cms_promote_cat' ) );
$form->add( new \IPS\Helpers\Form\Select(
'cms_promote_groups',
\IPS\Settings::i()->cms_promote_groups != '' ? ( \IPS\Settings::i()->cms_promote_groups === '*' ? '*' : explode( ",", \IPS\Settings::i()->cms_promote_groups ) ) : '*',
FALSE,
array( 'options' => \IPS\Member\Group::groups(), 'multiple' => TRUE, 'parse' => 'normal', 'unlimited' => '*', 'unlimitedLang' => 'all' ),
NULL,
NULL,
NULL,
'cms_promote_groups'
) );
if ( $values = $form->values() )
{
$form->saveAsSettings();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=cms&module=databases&controller=databases" ), 'saved' );
}
/* Display */
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( \IPS\Member::loggedIn()->language()->addToStack('cms_pages_settings'), $form, FALSE );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('cms_pages_settings');
}
/**
* Add/Edit
*
@@ -1078,7 +1126,7 @@ class _databases extends \IPS\Node\Controller
$form = new \IPS\Helpers\Form( 'form', 'save', NULL, array( 'data-controller' => 'cms.admin.databases.form' ) );
$form->addtab( 'content_database_form_details' );
$form->addTab( 'content_database_form_details' );
$form->add( new \IPS\Helpers\Form\Translatable( 'database_name', NULL, TRUE, array( 'app' => 'cms', 'key' => ( ! empty( $current ) ? "content_db_" . $current->id : NULL ) ) ) );
@@ -1126,13 +1174,15 @@ class _databases extends \IPS\Node\Controller
$templatesForm[ $template->group ] = $title;
break;
case 'category_articles':
case 'category_2_column_first_featured':
case 'category_2_column_image_feature':
case 'category_3_column_image_feature':
case 'category_3_column_first_featured':
$templatesFeatured[ $template->group ] = $title;
break;
}
}
$form->addSeparator();
$form->add( new \IPS\Helpers\Form\Radio( 'database_cat_index_type' , $current ? $current->cat_index_type : 0, FALSE, array(
'options' => array(
0 => 'database_display_index_as_categories',
@@ -1140,7 +1190,7 @@ class _databases extends \IPS\Node\Controller
),
'toggles' => array(
'0' => array( 'database_template_categories' ),
'1' => array( 'database_template_featured', 'database_featured_featured', 'database_featured_categories', 'database_featured_perpage', 'database_featured_pagination', 'database_featured_sort', 'database_featured_direction' )
'1' => array( $form->id . '_header_cms_articles_homepage_form', 'database_template_featured', 'database_featured_featured', 'database_featured_categories', 'database_featured_perpage', 'database_featured_pagination', 'database_featured_sort', 'database_featured_direction' )
)
), NULL, NULL, NULL, 'database_cat_index_type' ) );
@@ -1167,7 +1217,8 @@ class _databases extends \IPS\Node\Controller
}
}
$form->add( new \IPS\Helpers\Form\Select( 'database_template_categories', ! empty( $current ) ? $current->template_categories : NULL, FALSE, array( 'options' => $templatesCat ), NULL, NULL, NULL, 'database_template_categories' ) );
$form->addHeader("cms_articles_homepage_form");
$form->add( new \IPS\Helpers\Form\Select( 'database_template_featured', ! empty( $current ) ? $current->template_featured : NULL, FALSE, array( 'options' => $templatesFeatured ), NULL, NULL, NULL, 'database_template_featured' ) );
/* Featured settings */
@@ -1194,14 +1245,13 @@ class _databases extends \IPS\Node\Controller
)
), NULL, NULL, NULL, 'database_featured_direction' ) );
$form->addSeparator();
$form->addHeader( 'cms_database_form_display' );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_categories', ! empty( $current ) ? $current->template_categories : NULL, FALSE, array( 'options' => $templatesCat ), NULL, NULL, NULL, 'database_template_categories' ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_listing' , ! empty( $current ) ? $current->template_listing : NULL, FALSE, array( 'options' => $templatesList ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_display' , ! empty( $current ) ? $current->template_display : NULL, FALSE, array( 'options' => $templatesDisplay ) ) );
$form->add( new \IPS\Helpers\Form\Select( 'database_template_form' , ! empty( $current ) ? $current->template_form : NULL, FALSE, array( 'options' => $templatesForm ) ) );
$form->addHeader( 'cms_database_form_display' );
$form->add( new \IPS\Helpers\Form\Text( 'database_key', ! empty( $current ) ? $current->key : FALSE, FALSE, array(), function( $val )
{
try
@@ -1240,7 +1290,7 @@ class _databases extends \IPS\Node\Controller
return true;
} ) );
$form->addtab( 'content_database_form_lang' );
$form->addTab( 'content_database_form_lang' );
$sl_Default = null;
$pl_Default = null;
@@ -1266,7 +1316,7 @@ class _databases extends \IPS\Node\Controller
$form->add( new \IPS\Helpers\Form\Translatable( 'database_lang_pu', $pu_Default, FALSE, array( 'app' => 'cms', 'key' => ( ! empty( $current ) ? "content_db_lang_pu_" . $current->id : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'database_lang_ia', $ia_Default, FALSE, array( 'app' => 'cms', 'key' => ( ! empty( $current ) ? "content_db_lang_ia_" . $current->id : NULL ) ) ) );
$form->addtab( 'content_database_form_options' );
$form->addTab( 'content_database_form_options' );
$form->add( new \IPS\Helpers\Form\YesNo( 'database_all_editable' , $current ? $current->all_editable : FALSE, FALSE, array( 'togglesOff' => array( 'cms_bitoptions_indefinite_own_edit' ) ) ) );
$form->add( new \IPS\Helpers\Form\YesNo( 'cms_bitoptions_indefinite_own_edit' , $current ? $current->options['indefinite_own_edit'] : FALSE, FALSE, array(), NULL, NULL, NULL, 'cms_bitoptions_indefinite_own_edit' ) );
@@ -1335,6 +1385,10 @@ class _databases extends \IPS\Node\Controller
$thumbWidthHeight = $ffsettings['record_image']['thumb_dims'];
}
}
else
{
$recordImagesOn = TRUE;
}
$form->add( new \IPS\Helpers\Form\YesNo( 'database_record_image' , $recordImagesOn, FALSE, array( 'togglesOn' => array( 'fixed_field_setting__record_image__image_dims', 'fixed_field_setting__record_image__thumb_dims' ) ), NULL, NULL, NULL, 'database_record_image' ) );
$form->add( new \IPS\Helpers\Form\WidthHeight( 'fixed_field_setting__record_image__image_dims', ( $current AND $widthHeight !== NULL ) ? $widthHeight : array( 0, 0 ), FALSE, array( 'resizableDiv' => FALSE, 'unlimited' => array( 0, 0 ) ), NULL, NULL, NULL, 'fixed_field_setting__record_image__image_dims' ) );
@@ -1411,12 +1465,34 @@ class _databases extends \IPS\Node\Controller
}
}, NULL, NULL, 'page_name' );
}
if ( $name !== 'page_content' AND $name !== 'tab_content' )
{
$pageToggles[] = $name;
$pageFormFields[ $name ] = $field;
}
if ( $name === 'page_folder_id' )
{
$pageFormFields['page_type'] = new \IPS\Helpers\Form\Radio(
'page_type', 'builder', FALSE, array(
'options' => array(
'builder' => 'page_type_builder',
'html' => 'page_type_manual'
),
'descriptions' => array(
'builder' => 'page_type_builder_desc',
'html' => 'page_type_manual_custom_desc'
),
'toggles' => array(
'builder' => array( 'page_template' ),
'html' => array( 'page_show_sidebar', 'page_wrapper_template', 'page_ipb_wrapper' )
)
), NULL, NULL, NULL, 'page_type'
);
$pageToggles[] = 'page_type';
}
}
$form->add( new \IPS\Helpers\Form\Radio( 'database_create_page', 'existing', FALSE, array(
@@ -1652,8 +1728,6 @@ class _databases extends \IPS\Node\Controller
{
if ( $values['database_create_page'] === 'new' )
{
$values['page_content'] = '{database="' . $current->id . '"}';
$pageValues = array();
foreach( $values as $k => $v )
@@ -1664,7 +1738,23 @@ class _databases extends \IPS\Node\Controller
}
}
$pageId = \IPS\cms\Pages\Page::createFromForm( $pageValues, 'html' );
if ( $values['page_type'] === 'html' )
{
$pageValues['page_content'] = '{database="' . $current->id . '"}';
$pageValues['page_template'] = '';
}
$newPage = \IPS\cms\Pages\Page::createFromForm( $pageValues, 'html' );
if ( $values['page_type'] !== 'html' )
{
\IPS\Db::i()->insert( 'cms_page_widget_areas', array(
'area_page_id' => $newPage->id,
'area_widgets' => json_encode( array( array( 'app' => 'cms', 'key' => 'Database', 'unique' => uniqid(), 'configuration' => array( 'database' => $current->id ) ) ) ),
'area_area' => 'col1',
'area_orientation' => 'horizontal'
) );
}
}
}
else
@@ -43,6 +43,15 @@ class _records extends \IPS\Dispatcher\Controller
*/
protected function manage()
{
/* There may be no database ID if the admin only has permission to view records and not the database list itself */
if ( !\IPS\Request::i()->database_id )
{
foreach ( \IPS\cms\Databases::databases() as $database )
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=databases&controller=records&do=manage&database_id=' . $database->_id ) );
}
}
$database = \IPS\cms\Databases::load( \IPS\Request::i()->database_id );
$title = \IPS\Member::loggedIn()->language()->addToStack('content_record_db_title', TRUE, array( 'sprintf' => array( $database->_title ) ) );
@@ -328,7 +337,7 @@ class _records extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form();
$form->addtab( 'content_database_record_tab_content' );
$form->addTab( 'content_database_record_tab_content' );
$formElements = $class::formElements( $current, $container );
@@ -353,7 +362,7 @@ class _records extends \IPS\Dispatcher\Controller
$form->add( $obj );
}
$form->addtab( 'content_database_record_tab_publish' );
$form->addTab( 'content_database_record_tab_publish' );
if ( isset( $formElements['record_publish_date'] ) )
{
@@ -364,18 +373,26 @@ class _records extends \IPS\Dispatcher\Controller
{
$form->add( $formElements['record_expiry_date'] );
}
$form->add( new \IPS\Helpers\Form\Radio( 'record_author_choice', $current ? ( $current->member_id === \IPS\Member::loggedIn()->member_id ? 'me' : 'notme' ) : 'me', FALSE, array(
'options' => array(
'me' => 'record_author_choice_me',
'notme' => 'record_author_choice_notme'
),
$currentMember = ( $current ? \IPS\Member::load( $current->member_id ) : NULL );
$options = array(
'me' => 'record_author_choice_me',
'notme' => 'record_author_choice_notme'
);
if ( $currentMember and ! $current->member_id )
{
$options['guest'] = 'record_author_choice_guest';
}
$form->add( new \IPS\Helpers\Form\Radio( 'record_author_choice', $currentMember ? ( $currentMember->member_id === \IPS\Member::loggedIn()->member_id ? 'me' : ( $currentMember->member_id ? 'notme' : 'guest' ) ) : 'me', FALSE, array(
'options' => $options,
'toggles' => array(
'notme' => array( 'record_member_id' )
)
), NULL, NULL, NULL, 'record_author_choice' ) );
$form->add( new \IPS\Helpers\Form\Member( 'record_member_id', ( $current ? \IPS\Member::load( $current->member_id ) : NULL ), FALSE, array(), NULL, NULL, NULL, 'record_member_id' ) );
$form->add( new \IPS\Helpers\Form\Member( 'record_member_id', ( $currentMember and $currentMember->member_id ) ? $currentMember : NULL, FALSE, array(), NULL, NULL, NULL, 'record_member_id' ) );
if ( isset( $formElements['record_allow_comments'] ) )
{
@@ -391,7 +408,7 @@ class _records extends \IPS\Dispatcher\Controller
if ( \IPS\Member::loggedIn()->modPermission('can_content_edit_meta_tags') )
{
$form->addtab( 'content_database_record_tab_meta' );
$form->addTab( 'content_database_record_tab_meta' );
$form->add( $formElements['record_meta_keywords'] );
$form->add( $formElements['record_meta_description'] );
}
@@ -435,13 +452,36 @@ class _records extends \IPS\Dispatcher\Controller
/* Other data */
$current->record_meta_keywords = $values['record_meta_keywords'];
$current->record_meta_description = $values['record_meta_description'];
$changeAuthor = FALSE;
if ( ! empty( \IPS\Request::i()->id ) and $values['record_author_choice'] === 'notme' and ! empty( $values['record_member_id'] ) )
{
$changeAuthor = TRUE;
}
$changeAuthor = FALSE;
if ( ! empty( \IPS\Request::i()->id ) )
{
if ( $values['record_author_choice'] === 'guest' )
{
if ( $current->member_id )
{
$values['record_member_id'] = new \IPS\Member;
$changeAuthor = TRUE;
}
}
else if ( ! $current->member_id and $values['record_author_choice'] !== 'guest' )
{
$values['record_member_id'] = \IPS\Member::loggedIn();
$changeAuthor = TRUE;
}
else if ( $values['record_author_choice'] === 'notme' and ! empty( $values['record_member_id'] ) )
{
$changeAuthor = TRUE;
}
}
else
{
if ( $values['record_author_choice'] === 'notme' and ! empty( $values['record_member_id'] ) )
{
$changeAuthor = TRUE;
}
}
/* Just editing, thanks */
if ( ! $new )
{
@@ -90,7 +90,10 @@ class _ajax extends \IPS\Dispatcher\Controller
$templateBits = \IPS\Theme::master()->getRawTemplates( $location['app'], $location['location'], $location['group'], \IPS\Theme::RETURN_ALL );
$templateBit = $templateBits[ $location['app'] ][ $location['location'] ][ $location['group'] ][ $location['name'] ];
$templateBit['template_content'] = htmlentities( $templateBit['template_content'], \IPS\HTMLENTITIES, 'UTF-8', TRUE );
if ( ! isset( \IPS\Request::i()->noencode ) OR ! \IPS\Request::i()->noencode )
{
$templateBit['template_content'] = htmlentities( $templateBit['template_content'], \IPS\HTMLENTITIES, 'UTF-8', TRUE );
}
$templateArray = array(
'template_id' => $templateBit['template_id'],
@@ -132,7 +135,7 @@ class _ajax extends \IPS\Dispatcher\Controller
'template_key' => $template->key,
'template_title' => $template->title,
'template_desc' => $template->desc,
'template_content' => htmlentities( $template->content, \IPS\HTMLENTITIES, 'UTF-8', TRUE ),
'template_content' => ( isset( \IPS\Request::i()->noencode ) AND \IPS\Request::i()->noencode ) ? $template->content : htmlentities( $template->content, \IPS\HTMLENTITIES, 'UTF-8', TRUE ),
'template_location' => $template->location,
'template_group' => $template->group,
'template_container' => $template->container,
@@ -138,17 +138,22 @@ class _blocks extends \IPS\Node\Controller
}
catch ( \OutOfRangeException $e ) { }
}
$disabled = array();
foreach( \IPS\cms\Databases::databases() as $db )
{
if ( $db->page_id )
{
$plugins[ \IPS\Member::loggedIn()->language()->addToStack( 'cms_db_feed_title' ) ][ 'db_feed_' . $db->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_db_feed_block_with_name', NULL, array( 'sprintf' => array( $db->_title ) ) );
}
else
{
$disabled[] = 'db_feed_' . $db->id;
$plugins[ \IPS\Member::loggedIn()->language()->addToStack( 'cms_db_feed_title' ) ][ 'db_feed_' . $db->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'cms_db_feed_block_with_name_disabled', NULL, array( 'sprintf' => array( $db->_title ) ) );
}
}
$form->add( new \IPS\Helpers\Form\Select( 'content_block_add_type_plugin', null, false, array( 'options' => $plugins ), NULL, NULL, NULL, 'content_block_add_type_plugin' ) );
$form->add( new \IPS\Helpers\Form\Select( 'content_block_add_type_plugin', null, false, array( 'options' => $plugins, 'disabled' => $disabled ), NULL, NULL, NULL, 'content_block_add_type_plugin' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'content_block_add_custom_type', 'editor', TRUE, array(
'options' => array( 'editor' => 'content_block_add_custom_type_wysiwyg',
@@ -180,4 +185,18 @@ class _blocks extends \IPS\Node\Controller
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( \IPS\Member::loggedIn()->language()->addToStack('content_block_block_add'), $form, FALSE );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('content_block_block_add');
}
/**
* View external embed options
*
* @return void
*/
public function embedOptions()
{
$block = \IPS\cms\Blocks\Block::load( \IPS\Request::i()->id );
$embedKey = md5( $block->key . time() );
/* Output */
\IPS\Output::i()->title = "External Embed"; // @todo
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( '', \IPS\Theme::i()->getTemplate( 'blocks', 'cms', 'admin' )->embedCode( $block, $embedKey ) );;
}
}
@@ -0,0 +1,410 @@
<?php
/**
* @brief Pages Media Management
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - 2015 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @subpackage Pages
* @since 07 Jul 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms\modules\admin\pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* media
*/
class _media extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = '\IPS\cms\Media\Folder';
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'media_manage' );
parent::execute();
}
/**
* Get Root Buttons
*
* @return array
*/
public function _getRootButtons()
{
$buttons = array();
if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'cms', 'pages', 'page_add' ) )
{
$buttons['add_folder'] = array(
'icon' => 'folder-open',
'title' => 'cms_add_media_folder',
'link' => \IPS\Http\Url::internal( 'app=cms&module=pages&controller=media&do=form' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_add_media_folder') )
);
$buttons['add_page'] = array(
'icon' => 'plus-circle',
'title' => 'cms_add_media',
'link' => \IPS\Http\Url::internal( 'app=cms&module=pages&controller=media&subnode=1&do=form' ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_add_media') )
);
}
return $buttons;
}
/**
* Delete many at once
*
* @return void
*/
public function deleteByFileIds()
{
if ( isset( \IPS\Request::i()->fileIds ) )
{
$ids = \IPS\Request::i()->fileIds;
if ( ! is_array( $ids ) )
{
$try = json_decode( $ids, TRUE );
if ( ! is_array( $try ) )
{
$ids = array( $ids );
}
else
{
$ids = $try;
}
}
if ( count( $ids ) )
{
\IPS\cms\Media::deleteByFileIds( $ids );
}
}
}
/**
* Show the pages tree
*
* @return string
*/
protected function manage()
{
$url = \IPS\Http\Url::internal( "app=cms&module=pages&controller=media" );
/* Display the table */
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__cms_pages_media');
$output = new \IPS\Helpers\Tree\Tree( $url, 'menu__cms_pages_media',
/* Get Roots */
function () use ( $url )
{
$data = \IPS\cms\modules\admin\pages\media::getRowsForTree( 0 );
$rows = array();
foreach ( $data as $id => $row )
{
if( ( \IPS\Request::i()->isAjax() && $row instanceof \IPS\cms\Media ) || !\IPS\Request::i()->isAjax() )
{
$rows[ $id ] = ( $row instanceof \IPS\cms\Media) ? \IPS\cms\modules\admin\pages\media::getItemRow( $row, $url ) : \IPS\cms\modules\admin\pages\media::getFolderRow( $row, $url );
}
}
if( \IPS\Request::i()->isAjax() ){
\IPS\Output::i()->sendOutput( json_encode( $rows ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
}
return $data;
},
/* Get Row */
function ( $id, $root ) use ( $url )
{
if ( $root )
{
return \IPS\cms\modules\admin\pages\media::getFolderRow( \IPS\cms\Media\Folder::load( $id ), $url );
}
else
{
return \IPS\cms\modules\admin\pages\media::getItemRow( \IPS\cms\Media::load( $id ), $url );
}
},
/* Get Row Parent ID*/
function ()
{
return NULL;
},
/* Get Children */
function ( $id ) use ( $url )
{
$rows = array();
$data = \IPS\cms\modules\admin\pages\media::getRowsForTree( $id );
if ( ! isset( \IPS\Request::i()->subnode ) )
{
foreach ( $data as $id => $row )
{
if( \IPS\Request::i()->get == 'folders' && !( $row instanceof \IPS\cms\Media ) )
{
$rows[ $id ] = \IPS\cms\modules\admin\pages\media::getFolderRow( $row, $url );
}
elseif ( \IPS\Request::i()->get == 'files' && $row instanceof \IPS\cms\Media )
{
$rows[ $id ] = \IPS\cms\modules\admin\pages\media::getItemRow( $row, $url );
}
}
}
if( \IPS\Request::i()->isAjax() ){
\IPS\Output::i()->sendOutput( json_encode( $rows ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
}
return $rows;
},
array( $this, '_getRootButtons' ),
TRUE,
FALSE,
FALSE
);
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_media.js', 'cms' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'media/media.css', 'cms', 'admin' ) );
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( $output, 200, 'text/html', \IPS\Output::i()->httpHeaders );
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'media', 'cms', 'admin' )->media( $output );
}
}
/**
* Upload items
*
* @return void
*/
public function upload()
{
$form = new \IPS\Helpers\Form( 'form', 'upload' );
$form->class = 'ipsForm_vertical ipsForm_noLabels';
$form->add( new \IPS\Helpers\Form\Upload( 'media_filename', NULL, FALSE, array( 'allowedFileTypes' => \IPS\File::$safeFileExtensions, 'obscure' => FALSE, 'maxFileSize' => 5, 'storageExtension' => 'core_Theme', 'storageContainer' => 'pages_media', 'multiple' => true, 'minimize' => FALSE ), NULL, NULL, NULL, 'media_filename' ) );
if ( ! isset( \IPS\Request::i()->media_parent ) and ! \IPS\Request::i()->media_parent )
{
$form->add( new \IPS\Helpers\Form\Node( 'media_parent', 0, FALSE, array(
'class' => '\IPS\cms\Media\Folder',
'zeroVal' => 'node_no_parent'
) ) );
}
else
{
$form->hiddenValues['media_parent_inline'] = \IPS\Request::i()->media_parent;
}
if ( $values = $form->values() )
{
$parent = 0;
$count = 0;
if ( isset( $values['media_parent_inline'] ) AND $values['media_parent_inline'] )
{
$parent = $values['media_parent_inline'];
}
else
{
if ( isset( $values['media_parent'] ) AND ( ! empty( $values['media_parent'] ) OR $values['media_parent'] === 0 ) )
{
$parent = ( $values['media_parent'] === 0 ) ? 0 : $values['media_parent']->id;
}
}
foreach( $values['media_filename'] as $media )
{
$filename = $media->originalFilename;
$prefix = $parent . '_';
if ( mb_strstr( $filename, $prefix ) )
{
$filename = mb_substr( $filename, mb_strlen( $prefix ) );
}
$new = new \IPS\cms\Media;
$new->filename = $filename;
$new->filename_stored = $parent . '_' . $filename;
$new->is_image = $media->isImage();
$new->parent = $parent;
$new->added = time();
$new->file_object = (string) \IPS\File::create( 'cms_Media', $new->filename_stored, $media->contents(), 'pages_media', TRUE, NULL, FALSE );
$new->save();
$new->setFullPath( ( $parent ? \IPS\cms\Media\Folder::load( $parent )->path : '' ) );
$new->save();
$count++;
}
if ( \IPS\Request::i()->isAjax() )
{
$url = \IPS\Http\Url::internal( "app=cms&module=pages&controller=media" );
$data = \IPS\cms\modules\admin\pages\media::getRowsForTree( $parent );
$rows = array();
foreach ( $data as $id => $row )
{
if ( $row instanceof \IPS\cms\Media )
{
$rows[ $id ] = \IPS\cms\modules\admin\pages\media::getItemRow( $row, $url );
}
}
\IPS\Output::i()->sendOutput( json_encode( array( 'count' => $count, 'folderID' => $parent, 'rows' => $rows ) ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=media' ) );
}
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( 'upload', $form, FALSE );
}
/**
* Tree Search
*
* @return void
*/
protected function search()
{
$rows = array();
$url = \IPS\Http\Url::internal( "app=cms&module=pages&controller=media" );
/* Get results */
$items = \IPS\cms\Media::search( 'media_filename', \IPS\Request::i()->input, 'media_filename' );
/* Convert to HTML */
foreach ( $items as $id => $result )
{
$rows[ $id ] = $this->getItemRow( $result, $url );
}
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->sendOutput( json_encode( $rows ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
}
else
{
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'trees', 'core' )->rows( $rows, '' );
}
}
/**
* Returns a JSON object with some file information
*
* @return void
*/
protected function getFileInfo()
{
try
{
$row = \IPS\cms\Media::load( \IPS\Request::i()->id );
$fileObject = \IPS\File::get( 'cms_Media', $row->file_object );
}
catch( \OutOfRangeException $ex )
{
return;
}
/* Make a human-readable size */
$filesize = \IPS\Output\Plugin\Filesize::humanReadableFilesize( $fileObject->filesize() );
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $filesize );
$output = array(
'fileSize' => $filesize,
'dimensions' => NULL
);
/* If this is an image we'll also show the dimensions */
if( $row->is_image )
{
$dimensions = $fileObject->getImageDimensions();
$output['dimensions'] = $dimensions[0] . ' x ' . $dimensions[1];
}
\IPS\Output::i()->sendOutput( json_encode( $output ), 200, 'application/json', \IPS\Output::i()->httpHeaders );
}
/**
* Return HTML for a page row
*
* @param array $row Row data
* @param object $url \IPS\Http\Url object
* @return string HTML
*/
public static function getItemRow( $item, $url )
{
return \IPS\Theme::i()->getTemplate( 'media', 'cms', 'admin' )->fileListing( $url, $item );
}
/**
* Return HTML for a folder row
*
* @param array $row Row data
* @param object $url \IPS\Http\Url object
* @return string HTML
*/
public static function getFolderRow( $folder, $url )
{
return \IPS\Theme::i()->getTemplate( 'media', 'cms', 'admin' )->folderRow( $url, $folder );
}
/**
* Fetch rows of folders/pages
*
* @param int $folderId Parent ID to fetch from
*/
public static function getRowsForTree( $folderId=0 )
{
try
{
if ( $folderId === 0 )
{
$folders = \IPS\cms\Media\Folder::roots();
}
else
{
$folders = \IPS\cms\Media\Folder::load( $folderId )->children( NULL, NULL, FALSE );
}
}
catch( \OutOfRangeException $ex )
{
$folders = array();
}
$media = \IPS\cms\Media::getChildren( $folderId );
return \IPS\cms\Media\Folder::munge( $folders, $media );
}
}
@@ -1,69 +0,0 @@
<?php
/**
* @brief Page menu Controller
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 15 Sept 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms\modules\admin\pages;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Page management
*/
class _menu extends \IPS\Node\Controller
{
/**
* Node Class
*/
protected $nodeClass = '\IPS\cms\Pages\Menu';
/**
* Execute
*
* @return void
*/
public function execute()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'menu_manage' );
parent::execute();
}
/**
* Show the pages tree
*
* @return string
*/
protected function manage()
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__cms_pages_menu');
if ( ! \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( \IPS\Member::loggedIn()->language()->addToStack('cms_menu_information'), 'information', NULL, FALSE );
}
return parent::manage();
}
/**
* Delete
*
* @return void
*/
protected function delete()
{
unset( \IPS\Data\Store::i()->cms_menu );
parent::delete();
}
}
+14 -6
View File
@@ -153,7 +153,7 @@ class _pages extends \IPS\Node\Controller
$options = array();
$url['path'] = preg_replace( '#^/?(.+?)?/?$#', '\1', $url['path'] );
$disabled = ( $url['path'] ) ? FALSE : TRUE;
$disabled = ( \IPS\Settings::i()->cms_use_different_gateway or $url['path'] ) ? FALSE : TRUE;
$dirs = explode( '/', $url['path'] );
if ( count( $dirs ) )
@@ -213,13 +213,21 @@ class _pages extends \IPS\Node\Controller
}
}, NULL, NULL, 'cms_root_page_url' ) );
$form->add( new \IPS\Helpers\Form\Node( 'cms_error_page', \IPS\Settings::i()->cms_error_page ? \IPS\Settings::i()->cms_error_page : 0, FALSE,array(
'class' => '\IPS\cms\Pages\Page',
'zeroVal' => 'cms_error_page_none',
'subnodes' => true,
'permissionCheck' => function( $node )
{
return $node->type == 'html';
}
) ) );
if ( $values = $form->values() )
{
$form->saveAsSettings();
\IPS\Member::clearCreateMenu();
\IPS\cms\Pages\Menu::clearCaches();
/* Clear Sidebar Caches */
\IPS\Widget::deleteCaches();
@@ -231,7 +239,7 @@ class _pages extends \IPS\Node\Controller
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('cms_pages_settings');
}
/**
/**
* Download .htaccess file
*
* @return void
@@ -344,7 +352,7 @@ FILE;
/* Convert to HTML */
foreach ( $results as $id => $result )
{
$rows[ $id ] = ( $result instanceof \IPS\cms\Pages\Page ) ? $this->_getPageRow( $result, $url ) : $this->_getFolderRow( $result, $url );
$rows[ $id ] = ( $result instanceof \IPS\cms\Pages\Page ) ? $this->getPageRow( $result, $url ) : $this->getFolderRow( $result, $url );
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'trees', 'core' )->rows( $rows, '' );
@@ -46,7 +46,292 @@ class _templates extends \IPS\Dispatcher\Controller
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates' ), 'completed' );
}
/**
* Import dialog
*
* @return void
*/
public function import()
{
$form = new \IPS\Helpers\Form( 'form', 'next' );
$form->add( new \IPS\Helpers\Form\Upload( 'cms_templates_import', NULL, FALSE, array( 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ), NULL, NULL, NULL, 'cms_templates_import' ) );
if ( $values = $form->values() )
{
if ( $values['cms_templates_import'] )
{
/* Move it to a temporary location */
$tempFile = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
move_uploaded_file( $values['cms_templates_import'], $tempFile );
/* Initate a redirector */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=importProcess&file=' . urlencode( $tempFile ) . '&key=' . md5_file( $tempFile ) ) );
}
else
{
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=manage' ) );
}
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( 'cms_templates_import_title', $form, FALSE );
}
/**
* Import from upload
*
* @return void
*/
public function importProcess()
{
if ( !file_exists( \IPS\Request::i()->file ) or md5_file( \IPS\Request::i()->file ) !== \IPS\Request::i()->key )
{
\IPS\Output::i()->error( 'generic_error', '3T259/3', 403, '' );
}
/* Open XML file */
$xml = new \XMLReader;
$xml->open( \IPS\Request::i()->file );
$prefix = date('m') . '.' . date('d') . '.' . date('y') . '_';
if ( ! @$xml->read() )
{
\IPS\Output::i()->error( 'xml_upload_invalid', '2C163/1', 403, '' );
}
$xml->read();
while ( $xml->read() )
{
if ( $xml->name === 'template' )
{
$templates = \IPS\cms\Theme::i()->getRawTemplates( 'cms', NULL, NULL, \IPS\cms\Theme::RETURN_ALL );
$node = new \SimpleXMLElement( $xml->readOuterXML() );
$attrs = array();
foreach( $node->attributes() as $k => $v )
{
$attrs[ $k ] = (string) $v;
}
/* Any kids of your own? */
foreach( $node->children() as $k => $v )
{
$tryJson = json_decode( $v, TRUE );
$attrs[ $k ] = ( $tryJson ) ? $tryJson : (string) $v;
}
if ( isset( $attrs['template_title'] ) and isset( $attrs['template_location'] ) and isset( $attrs['template_group'] ) )
{
/* Got this template? */
if ( $attrs['template_location'] === 'database' )
{
/* Database templates are really governed by the group as they are a collection of templates */
if ( isset( $templates['cms'][$attrs['template_location']][$attrs['template_group']] ) )
{
$attrs['template_group'] = $prefix . $attrs['template_group'];
}
}
else
{
/* But post and block templates are not */
if ( isset( $templates['cms'][$attrs['template_location']][$attrs['template_group']] ) )
{
$exists = FALSE;
foreach ( $templates['cms'][$attrs['template_location']][$attrs['template_group']] as $key => $template )
{
if ( $template['template_title'] === $attrs['template_title'] )
{
$exists = TRUE;
break;
}
}
if ( $exists )
{
$attrs['template_title'] = $prefix . $attrs['template_title'];
}
}
}
$obj = new \IPS\cms\Templates;
$obj->location = $attrs['template_location'];
$obj->group = $attrs['template_group'];
$obj->title = $attrs['template_title'];
$obj->params = $attrs['template_params'];
$obj->content = $attrs['template_content'];
$obj->original_group = $attrs['template_original_group'];
$obj->type = 'template';
$obj->user_created = 1;
$obj->user_edited = 1;
$obj->desc = '';
$obj->save();
$obj->key = $obj->location . \IPS\Http\Url::seoTitle( $obj->group ) . '_' . \IPS\Http\Url::seoTitle( $obj->title ) . '_' . $obj->id;
$obj->save();
}
}
$xml->next();
}
/* Done */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=manage' ), 'cms_templates_imported' );
}
/**
* Export templates
*
* @return void
*/
public function export()
{
$form = new \IPS\Helpers\Form( 'form', 'next' );
$templates = array();
$form->addMessage( 'cms_templates_export_description', 'ipsMessage ipsMessage_information' );
foreach( \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_DATABASE_ONLY + \IPS\cms\Templates::RETURN_ALL ) as $template )
{
$title = \IPS\cms\Templates::readableGroupName( $template->group );
if ( $template->location === 'database' )
{
$templates['database'][ $template->group ] = $title;
}
else if ( $template->location === 'block' )
{
$templates['block'][ $template->key ] = $title . ' &gt; ' . $template->title;
}
else if ( $template->location === 'page' )
{
$templates['page'][ $template->key ] = $title . ' &gt; ' . $template->title;
}
}
foreach( $templates as $location => $data )
{
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'templates_' . $location, FALSE, FALSE, array( 'options' => $data ) ) );
}
if ( $values = $form->values() )
{
$exportTemplates = array();
foreach( $templates as $location => $data )
{
if ( isset( $values[ 'templates_' . $location ] ) and count( $values[ 'templates_' . $location ] ) )
{
if ( $location === 'database' )
{
$tmp = \IPS\cms\Theme::i()->getRawTemplates( 'cms', array('database'), array_values( $values[ 'templates_' . $location ] ) );
foreach( $tmp['cms'] as $loc => $data )
{
if ( $loc === $location )
{
foreach ( $data as $key => $tdata )
{
foreach ( $tdata as $tkey => $tkdata )
{
$exportTemplates['cms'][ $location ][ $key ][ $tkey ] = $tkdata;
}
}
}
}
}
else
{
$tmp = \IPS\cms\Theme::i()->getRawTemplates( 'cms', array( $location ), NULL, \IPS\cms\Theme::RETURN_DATABASE_ONLY + \IPS\cms\Theme::RETURN_ALL );
foreach( $tmp['cms'] as $loc => $data )
{
if ( $loc === $location )
{
foreach( $data as $key => $tdata )
{
foreach( $tdata as $tkey => $tkdata )
{
if ( in_array( $tkey, $values[ 'templates_' . $location ] ) )
{
$exportTemplates['cms'][ $location ][ $key ][ $tkey ] = $tkdata;
}
}
}
}
}
}
}
}
if ( count( $exportTemplates ) )
{
/* Init */
$xml = new \XMLWriter;
$xml->openMemory();
$xml->setIndent( TRUE );
$xml->startDocument( '1.0', 'UTF-8' );
/* Root tag */
$xml->startElement('templates');
foreach ( $exportTemplates as $app => $location )
{
foreach ( $location as $key => $data )
{
foreach ( $data as $group => $template )
{
foreach( $template as $key => $templateData )
{
/* Initiate the <template> tag */
$xml->startElement( 'template' );
foreach ( $templateData as $k => $v )
{
if ( ! in_array( \substr( $k, 9 ), array( 'content', 'params' ) ) )
{
$xml->startAttribute( $k );
$xml->text( $v );
$xml->endAttribute();
}
}
/* Write (potential) HTML fields */
foreach( array( 'template_params', 'template_content' ) as $field )
{
if ( isset( $templateData[ $field ] ) )
{
$xml->startElement( $field );
if ( preg_match( '/<|>|&/', $templateData[ $field ] ) )
{
$xml->writeCData( str_replace( ']]>', ']]]]><![CDATA[>', $templateData[ $field ] ) );
}
else
{
$xml->text( $templateData[ $field ] );
}
$xml->endElement();
}
}
/* Close the <template> tag */
$xml->endElement();
}
}
}
}
/* Finish */
$xml->endDocument();
\IPS\Output::i()->sendOutput( $xml->outputMemory(), 200, 'application/xml', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', "pages_templates.xml" ) ) );
}
else
{
\IPS\Output::i()->error( 'cms_no_templates_selected', '1T285/1', 403, '' );
}
}
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( 'cms_templates_export_title', $form, FALSE );
}
/**
* List templates
*
@@ -143,6 +428,20 @@ class _templates extends \IPS\Dispatcher\Controller
);
}
\IPS\Output::i()->sidebar['actions']['download'] = array(
'icon' => 'download',
'title' => 'cms_templates_export_title',
'link' => \IPS\Http\Url::internal( "app=cms&module=pages&controller=templates&do=export" ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_templates_export_title') )
);
\IPS\Output::i()->sidebar['actions']['upload'] = array(
'icon' => 'upload',
'title' => 'cms_templates_import_title',
'link' => \IPS\Http\Url::internal( "app=cms&module=pages&controller=templates&do=import" ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_templates_import_title') )
);
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/diff_match_patch.js', 'core', 'interface' ) );
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'codemirror/codemirror.js', 'core', 'interface' ) );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'codemirror/codemirror.css', 'core', 'interface' ) );
@@ -214,7 +513,7 @@ class _templates extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form();
$form->hiddenValues['type'] = $type;
$form->add( new \IPS\Helpers\Form\Text( 'template_title', NULL, TRUE ) );
$form->add( new \IPS\Helpers\Form\Text( 'template_title', NULL, TRUE, array( 'regex' => '/^([A-Z0-9_]+?)$/i' ) ) );
/* Very specific */
if ( $type === 'database' )
@@ -570,7 +869,10 @@ class _templates extends \IPS\Dispatcher\Controller
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* Clear block caches */
\IPS\cms\Blocks\Block::deleteCompiled();
if( \IPS\Request::i()->isAjax() )
{
\IPS\Output::i()->json( array( 'template_id' => $obj->id, 'template_title' => $obj->title, 'template_container' => $obj->container, 'template_user_added' => $obj->user_created ) );
@@ -22,7 +22,7 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
/**
* Ajax only methods
*/
class _ajax extends \IPS\Content\Controller
class _ajax extends \IPS\Dispatcher\Controller
{
/**
* Return a FURL
@@ -33,5 +33,42 @@ class _ajax extends \IPS\Content\Controller
{
return \IPS\Output::i()->json( array( 'slug' => \IPS\Http\Url::seoTitle( \IPS\Request::i()->slug ) ) );
}
/**
* Find Record
*
* @retun void
*/
public function findRecord()
{
$results = array();
$database = \IPS\cms\Databases::load( \IPS\Request::i()->id );
$input = mb_strtolower( \IPS\Request::i()->input );
$field = "field_" . $database->field_title;
$class = '\IPS\cms\Records' . $database->id;
$category = '';
$where = array( $field . " LIKE CONCAT('%', ?, '%')" );
$binds = array( $input );
foreach ( \IPS\Db::i()->select( '*', 'cms_custom_database_' . $database->id, array_merge( array( implode( ' OR ', $where ) ), $binds ), 'LENGTH(' . $field . ') ASC', array( 0, 20 ) ) as $row )
{
$record = $class::constructFromData( $row );
if ( $database->use_categories )
{
$category = \IPS\Member::loggedIn()->language()->addToStack( 'cms_autocomplete_category', NULL, array( 'sprintf' => array( $record->container()->_title ) ) );
}
$results[] = array(
'id' => $record->_id,
'value' => $record->_title,
'category' => $category,
'date' => \IPS\DateTime::ts( $record->record_publish_date )->html(),
);
}
\IPS\Output::i()->json( $results );
}
}
@@ -24,6 +24,13 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
class _category extends \IPS\cms\Databases\Controller
{
/**
* Store any active filters for this view
*
* @param array
*/
static public $activeFilters = array();
/**
* Determine which method to load
*
@@ -86,7 +93,6 @@ class _category extends \IPS\cms\Databases\Controller
}
/* Check cookie */
$activeFilters = array();
$where = array();
$cookie = $category->getFilterCookie();
if ( $cookie !== NULL )
@@ -120,7 +126,8 @@ class _category extends \IPS\cms\Databases\Controller
$where[] = array( mb_substr( $k, 8 ) . "=?", $v );
}
}
$activeFilters[ $f ] = array( 'field' => $customFields[ $f ], 'value' => $customFields[ $f ]->displayValue( $v ) );
static::$activeFilters[ $f ] = array( 'field' => $customFields[ $f ], 'value' => $customFields[ $f ]->displayValue( $v ) );
}
}
}
@@ -130,7 +137,7 @@ class _category extends \IPS\cms\Databases\Controller
$where = NULL;
}
$table = new \IPS\Helpers\Table\Content( 'IPS\cms\Records' . \IPS\cms\Databases\Dispatcher::i()->databaseId, $category->url(), $where, $category, NULL );
$table = new \IPS\Helpers\Table\Content( 'IPS\cms\Records' . \IPS\cms\Databases\Dispatcher::i()->databaseId, $category->url(), $where, $category, NULL, 'view', isset( \IPS\Request::i()->rss ) ? FALSE : TRUE );
$table->tableTemplate = array( \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' ), 'categoryTable' );
$table->rowsTemplate = array( \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' ), 'recordRow' );
$table->baseUrl = $table->baseUrl->setQueryString( 'd', \IPS\cms\Databases\Dispatcher::i()->databaseId );
@@ -231,8 +238,8 @@ class _category extends \IPS\cms\Databases\Controller
$table->advancedSearch = array(
'record_type' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $filterOptions ) ),
'sortby' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $sortBy ) ),
'sortdirection' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => array(
'sort_by' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $sortBy ) ),
'sort_direction' => array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => array(
'asc' => 'asc',
'desc' => 'desc',
) )
@@ -246,13 +253,13 @@ class _category extends \IPS\cms\Databases\Controller
{
\IPS\Member::loggedIn()->language()->words['content_field_' . $obj->id ] = $obj->_title;
$table->advancedSearch[ 'content_field_' . $obj->id ] = array( \IPS\Helpers\Table\SEARCH_SELECT, array( 'options' => $obj->extra, 'multiple' => TRUE, 'noDefault' => true ) );
$table->advancedSearch['sortby'][1]['options']['field_' . $obj->id ] = 'content_field_' . $obj->id;
$table->advancedSearch['sort_by'][1]['options']['field_' . $obj->id ] = 'content_field_' . $obj->id;
}
$table->sortOptions[ 'field_' . $obj->id ] = 'field_' . $obj->id;
}
$table->advancedSearchCallback = function( $table, $values ) use ( $database, $sortBy )
$table->advancedSearchCallback = function( $table, $values ) use ( $database, $sortBy, $customFields )
{
/* Type */
foreach( $values as $k => $v )
@@ -286,6 +293,9 @@ class _category extends \IPS\cms\Databases\Controller
}
}
}
$key = mb_substr( $k, 14 );
\IPS\cms\modules\front\database\category::$activeFilters[ $key ] = array( 'field' => $customFields[ $key ], 'value' => $customFields[ $key ]->displayValue( $v ) );
}
}
@@ -303,10 +313,10 @@ class _category extends \IPS\cms\Databases\Controller
}
/* Sort */
if ( isset( $values['sortby'] ) and isset( $sortBy[ $values['sortby'] ] ) )
if ( isset( $values['sort_by'] ) and isset( $sortBy[ $values['sort_by'] ] ) )
{
$table->sortBy = $values['sortby'];
$table->sortDirection = $values['sortdirection'];
$table->sortBy = $values['sort_by'];
$table->sortDirection = $values['sort_direction'];
}
/* Cutoff */
@@ -374,7 +384,14 @@ class _category extends \IPS\cms\Databases\Controller
{
if ( ! $record->hidden() )
{
$document->addItem( $record->_title, $record->url(), $record->$contentField, \IPS\DateTime::ts( $record->record_last_comment ), $record->_id );
$content = $record->$contentField;
if ( $record->record_image )
{
$content = \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' )->rssItemWithImage( $content, $record->record_image );
}
$document->addItem( $record->_title, $record->url(), $content, \IPS\DateTime::ts( $record->record_last_comment ), $record->_id );
}
}
@@ -389,14 +406,14 @@ class _category extends \IPS\cms\Databases\Controller
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'records/list.css', 'cms', 'front' ) );
\IPS\cms\Databases\Dispatcher::i()->output .= \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' )->categoryHeader( $category, (string) $table, $activeFilters );
\IPS\cms\Databases\Dispatcher::i()->output .= \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' )->categoryHeader( $category, (string) $table, static::$activeFilters );
if ( ( $category->hasChildren() AND $category->show_records ) OR ! $category->hasChildren() )
{
\IPS\cms\Databases\Dispatcher::i()->output .= (string) $table;
}
\IPS\cms\Databases\Dispatcher::i()->output .= \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' )->categoryFooter( $category, (string) $table, $activeFilters );
\IPS\cms\Databases\Dispatcher::i()->output .= \IPS\cms\Theme::i()->getTemplate( $category->_template_listing, 'cms', 'database' )->categoryFooter( $category, (string) $table, static::$activeFilters );
}
/**
@@ -428,7 +445,9 @@ class _category extends \IPS\cms\Databases\Controller
$hasModOptions = TRUE;
}
\IPS\Output::i()->allowDefaultWidgets = FALSE;
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\cms\Pages\Page::$currentPage->getWidgets();
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\cms\Theme::i(), 'getTemplate' ), array( $database->template_form, 'cms', 'database' ) ), 'recordForm' ), NULL, $category, $database, \IPS\cms\Pages\Page::$currentPage, $title, $hasModOptions );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( $title );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'records/form.css', 'cms', 'front' ) );
@@ -96,17 +96,17 @@ class _index extends \IPS\cms\Databases\Controller
$where = ( $database->featured_settings['featured'] ) ? array( array( 'record_featured=?', 1 ) ) : NULL;
$articles = $recordClass::getItemsWithPermission( $where, 'record_pinned DESC, ' . $database->featured_settings['sort'] . ' ' . $database->featured_settings['direction'], array( $limit, $database->featured_settings['perpage'] ), 'read', FALSE, 0, NULL, FALSE, FALSE, FALSE, FALSE );
$articles = $recordClass::getItemsWithPermission( $where, 'record_pinned DESC, ' . $database->featured_settings['sort'] . ' ' . $database->featured_settings['direction'], array( $limit, $database->featured_settings['perpage'] ), 'read', NULL, 0, NULL, FALSE, FALSE, FALSE, FALSE );
if ( $database->featured_settings['pagination'] )
{
$count = $recordClass::getItemsWithPermission( $where, 'record_pinned DESC, ' . $database->featured_settings['sort'] . ' ' . $database->featured_settings['direction'], $database->featured_settings['perpage'], 'read', FALSE, 0, NULL, FALSE, FALSE, FALSE, TRUE );
$count = $recordClass::getItemsWithPermission( $where, 'record_pinned DESC, ' . $database->featured_settings['sort'] . ' ' . $database->featured_settings['direction'], $database->featured_settings['perpage'], 'read', NULL, 0, NULL, FALSE, FALSE, FALSE, TRUE );
}
/* Pagination */
$pagination = array(
'page' => $page,
'pages' => ( $count > 0 ) ? ceil( $count['cnt'] / $database->featured_settings['perpage'] ) : 1
'pages' => ( $count > 0 ) ? ceil( $count / $database->featured_settings['perpage'] ) : 1
);
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'database_index/featured.css', 'cms', 'front' ) );
@@ -56,12 +56,12 @@ class _record extends \IPS\Content\Controller
}
catch( \Exception $e )
{
\IPS\Output::i()->error( 'node_error', '3T252/1', 403, '' );
\IPS\Output::i()->error( 'node_error', '2T252/1', 403, '' );
}
if ( $record === NULL )
{
\IPS\Output::i()->error( 'node_error', '3T252/2', 403, '' );
\IPS\Output::i()->error( 'node_error', '2T252/2', 404, '' );
}
if ( \IPS\Request::i()->view )
@@ -86,8 +86,9 @@ class _record extends \IPS\Content\Controller
$FieldsClass = '\\IPS\\cms\\Fields' . $record::$customDatabaseId;
$updateFields = $FieldsClass::fields( $record->fieldValues(), 'edit', $record->container(), $FieldsClass::FIELD_SKIP_TITLE_CONTENT | $FieldsClass::FIELD_DISPLAY_COMMENTFORM );
$form = null;
if ( count( $updateFields ) )
/* We need edit permission to change the record */
if ( count( $updateFields ) and $record->canEdit() )
{
$form = new \IPS\Helpers\Form( 'update_record', 'update', $record->url()->setQueryString( array( 'd' => $record::$customDatabaseId ) ) );
$form->class = 'ipsForm_vertical';
@@ -101,11 +102,6 @@ class _record extends \IPS\Content\Controller
if ( $values = $form->values() )
{
if ( ! $record->canEdit() )
{
\IPS\Output::i()->error( 'module_no_permission', '2T252/3', 403, '' );
}
/* Custom fields */
$customValues = array();
$fieldsClass = 'IPS\cms\Fields' . $record::$customDatabaseId;
@@ -528,8 +524,10 @@ class _record extends \IPS\Content\Controller
\IPS\Output::i()->redirect( $record->url() );
}
\IPS\Output::i()->allowDefaultWidgets = FALSE;
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\cms\Pages\Page::$currentPage->getWidgets();
\IPS\Output::i()->output = $form->customTemplate( array( call_user_func_array( array( \IPS\cms\Theme::i(), 'getTemplate' ), array( $database->template_form, 'cms', 'database' ) ), 'recordForm' ), NULL, $category, $database, \IPS\cms\Pages\Page::$currentPage, $title, $hasModOptions );
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( $title );
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'records/form.css', 'cms', 'front' ) );
Loaded 100 of 1131 files, more files were not shown because too many files have changed in this diff. Show more