Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Help for implementing "Newest N media objects"
marcd
#1 Posted : Saturday, 14 November 2009 5:42:03 PM(UTC)
marcd

Rank: Advanced Member

Joined: 13/02/2009(UTC)
Posts: 53
Location: Zurich, Switzerland

Hi Roger,

As written in the previous post I try to implement a "newest N pictures" feature into GSP. Provider is done (at least I think *g*). Now I try to find the right place to start with the UI for this feature. It sould appear on the frontpage (root / toplevel gallery) of the gallery.

What I already found is that the control rendering the thumbs should inherit from GalleryControl. For its implementation I propably can take a look at the ThumbnailView (/Controls). But where to render that new control in? What is the rootalbum? Do I need to add it to pages/album.ascx and check (how?) if we are on the root level album?

Any hint would be great ;-)

Cheers,
Marc
Roger Martin
#2 Posted : Sunday, 15 November 2009 7:00:15 AM(UTC)
Roger Martin

Rank: Administration

Joined: 3/08/2007(UTC)
Posts: 3,298
Location: Fort Atkinson, WI

I don't quite understand what you mean about where to render the new control. Do you want this to look like the home page, except instead of displaying your top-level albums (that is, the root album), it displays that newest N pics? If so, I can give you the 30,000 foot view of how I would implement it.

1. Create a function that returns the latest N media objects as an IGalleryObjectCollection. Sounds like you may have already done this.

2. Copy the gs\pages\search.ascx control and name it something like newest.ascx. Don't forget to change the class name in the code-behind.

3. Look at how the function SearchGallery is used on the search page. Notice how the search page generates a list of media objects to display:

Code:
...
galleryObjects = HelperFunctions.SearchGallery(searchText, this.GetGalleryServerRolesForUser(), Util.IsAuthenticated);

if (galleryObjects != null)
{
    tv.GalleryObjectsDataSource = galleryObjects;
    ...
}
...


The variable "tv" is the thumbnail view control. You can assign any collection of media objects to this control - they can be scattered across various albums, just like they would be when searching. In your case, replace the call to HelperFunctions.SearchGallery with the call to your function to return the newest N pics.

4. Add the enum value "newest" to the PageId enum (CodeFiles\Global.cs). Make sure your enum value exactly matches the name of your control. That is, if your control is named newest.ascx, then the enum value must be "newest".

5. At this point you should be able to load a page with the latest N pics by adding the "g=newest" to the URL of your gallery (example: http://www.site.com/gallery/default.aspx?g=newest). If you want this control to be the default so that it will load with an URL like http://www.site.com/gallery/, modify Util.GetPage so that when a "g" query string is not present, it defaults to PageId.newest instead of PageId.album.

Hope this helps,
Roger Martin
Creator and Lead Developer of Gallery Server Pro
marcd
#3 Posted : Thursday, 19 November 2009 5:31:15 AM(UTC)
marcd

Rank: Advanced Member

Joined: 13/02/2009(UTC)
Posts: 53
Location: Zurich, Switzerland

Hi Roger,

Thanks for your help. The hint to the search-control is very good so I know how to render the list of mediaobjects. But I don't want to create/display a new page. I just like to "extend" the home page / root gallery to show the latest N pics and later on the latest N galleries just below the list of top-level-galleries.

For example:
On my gallery found here I like to show a separator below the four top-level galleries ("Diving", "Animals", "Hiking" and "Misc.") and then the list of - let's say the latest 10 media objects.
Then later on a again a separator followed by the latest 5 galleries (eg. with just a standard icon and a link next to it.

But first lets start with just the latest N media objects ;-) What control / page shows the "root gallery" (as shown at the link above).

Regards,
Marc

ps. Is it possible to get mail notification on replies in this forum? Just an idea ;-)
Roger Martin
#4 Posted : Thursday, 19 November 2009 10:13:00 AM(UTC)
Roger Martin

Rank: Administration

Joined: 3/08/2007(UTC)
Posts: 3,298
Location: Fort Atkinson, WI

You can get email notification by clicking the link Watch this topic from the Options button at the top of this thread.

As far as the root album, here is how a page load works:

1. You request an URL like http://www.marcduerst.com/gallery/. Notice it does not specify an album ID.

2. The default.aspx page has an instance of a Gallery control on it. This is a user control that acts as a container for your gallery. The code is at CodeFiles\Gallery.cs.

3. Gallery.cs has a function named LoadRequestedPage whose job is to figure out what to display. Since there are no query string parameters, it defaults to the album.ascx control. This control is instantiated and added to the page.

4. The album.ascx user control is designed to display an album. When the album ID is specified in the query string (example: default.aspx?aid=384), that album is shown. When no ID is specified - as in your case - it automatically defaults to the top level album.

Technically, album.ascx is simply a container for two more user controls, and it is *those* controls that show the correct album.

You might ask *how* do those controls know which is the root album? Good question. All user controls in the pages directory inherit from the base class GalleryPage. This class has a function GetAlbum. This is a Very Important function whose job is to determine which album must be displayed for any given page, and then retrieve that album.

In your case, one idea is to modify this function so that you add the latest N pics to the collection returned by this function. But then your new pics get shown right along side your others, and you probably don't want that.

What I would probably do is create a new user control that is based on the thumbnailview.ascx control. Then add logic in LoadRequestedPage to add this control to the page output in addition to the album control, but only when certain conditions are met (such as no query string parameters present).
Roger Martin
Creator and Lead Developer of Gallery Server Pro
marcd
#5 Posted : Friday, 20 November 2009 6:07:43 PM(UTC)
marcd

Rank: Advanced Member

Joined: 13/02/2009(UTC)
Posts: 53
Location: Zurich, Switzerland

oh thx, didn't see the options button yet. cool features in there *g*

great explanation about how things get loaded in GSP. that will help a lot so I can give it a try the on the next rainy weekend ;-)

cheers, marc
marcd
#6 Posted : Saturday, 2 January 2010 11:37:23 PM(UTC)
marcd

Rank: Advanced Member

Joined: 13/02/2009(UTC)
Posts: 53
Location: Zurich, Switzerland

Long time no hear - I know :-)
But finally in the new year I got the feature done and online *jipie*. Check out: http://www.marcduerst.com/gallery/

You see a H2-Break "Newest media" and then two lines with the 10 newest pictures.

Are you interested in getting the code for this? If you I can try to create a patch using my SVN. What I didn't do yet is MSSQL (as I have and use only SQLite) and configuration settings in the admin back-end. Maybe I'll try that later (On/Off and how many newest objects should be shown). I also need to clean up things a little bit as I mainly did a copy-paste the Thumbnail-control what have ways more in it then I actually need. But hey, its working ;-)

Cheers,
Marc
marcd
#7 Posted : Saturday, 2 January 2010 11:43:36 PM(UTC)
marcd

Rank: Advanced Member

Joined: 13/02/2009(UTC)
Posts: 53
Location: Zurich, Switzerland

Just found one little issue:

Then one of the new thumbs the next/previous buttons do not work. Maybe this is because of the missing album id in the params? What do you think?

Edit: Just saw that previous/next don't work anymore in general. I just had to do to an upgrade of installation before applying my lastest-objects-patch. Any idea why previous/next could be broken?

Edit: Tried to emoved the callback-stuff on the latest-thumbs-view but it seems not to solve the issue on my productive site. The local source-version (our original) does not have the problem. Hmm...??
marcd
#8 Posted : Sunday, 3 January 2010 1:11:33 AM(UTC)
marcd

Rank: Advanced Member

Joined: 13/02/2009(UTC)
Posts: 53
Location: Zurich, Switzerland

for me it looks like not all .js-scripts get loaded / can be found. maybe i missed something during upgrade?
marcd
#9 Posted : Sunday, 3 January 2010 1:21:33 AM(UTC)
marcd

Rank: Advanced Member

Joined: 13/02/2009(UTC)
Posts: 53
Location: Zurich, Switzerland

seems i finally found it: just switched to "release". published the website to temp-directory and uploaded ALL binaries - not only some specific. seems the binaries have dependencies on webresources by it generated at compile-time so if one needs to replace one of thouse DLL's also the one with the webresources needs to be replaced.
Roger Martin
#10 Posted : Sunday, 3 January 2010 2:15:21 PM(UTC)
Roger Martin

Rank: Administration

Joined: 3/08/2007(UTC)
Posts: 3,298
Location: Fort Atkinson, WI

Glad you figured it out. I like the aesthetics of your site - some day when I have more time I would like to talk to you about seeing if you wouldn't mind donating your design as a "skin" that ships with GSP.

I don't think you need to send me the code. I have already sketched out a rough draft of how I want to implement this feature in a generic way. But I am curious how you ended up doing it. Can you share a bit about your technique?
Roger Martin
Creator and Lead Developer of Gallery Server Pro
marcd
#11 Posted : Monday, 4 January 2010 4:44:00 AM(UTC)
marcd

Rank: Advanced Member

Joined: 13/02/2009(UTC)
Posts: 53
Location: Zurich, Switzerland

Hi Roger,

I'll try to give a brief overview how I did it.

First of all I've added a new function to the IDataProvider and its abstract implementation DataProvider:

IDataProvider.cs:
Code:

/// <summary>
/// Gets the latest <paramref name="countMediaObjects"/> from the whole gallery (no specific album).
/// </summary>
/// <param name="countMediaObjects">The count of media objects to return.</param>
/// <returns></returns>
System.Data.IDataReader MediaObject_GetDataReaderLatestMediaObjects(int countMediaObjects);

DataProvider.cs:
Code:

/// <inheritdoc />
public abstract IDataReader MediaObject_GetDataReaderLatestMediaObjects(int countMediaObjects);

Then I've implemented it in the SQLite provider like this:

SQLiteGalleryServerProProvider.cs:
Code:

public override System.Data.IDataReader MediaObject_GetDataReaderLatestMediaObjects(int countMediaObjects)
{
SQLiteConnection cn = GetDBConnectionForGallery();
using (SQLiteCommand cmd = cn.CreateCommand())
{
const string sql = @"
SELECT [gs_MediaObject].MediaObjectId
FROM [gs_MediaObject]
ORDER BY DateAdded DESC
LIMIT @Count;";
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@Count", countMediaObjects);

if (cn.State == ConnectionState.Closed)
cn.Open();

if (IsTransactionInProgress())
return cmd.ExecuteReader();
else
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
}

Note that I only retrieve the ID's for the newest N items; not the whole records. This is because later on I reuse your existing methods to retrieve, cache and materialize whole instances of media-objects.

Next I use the above dataprovider method in the factory like this:

Factory.cs:
Code:

/// <summary>
/// Gets the newest <paramref name="countMediaObjects"/> media objects (images etc.) from the database.
/// </summary>
/// <param name="countMediaObjects">The count newest media objects.</param>
/// <returns>The newest <paramref name="countMediaObjects"/> media objects (images etc.)</returns>
public static IGalleryObjectCollection GetLatestMediaObjects(int countMediaObjects)
{
IGalleryObjectCollection result = new GalleryObjectCollection();

IDataReader dr = null;
try
{
using (dr = Factory.GetDataProvider().MediaObject_GetDataReaderLatestMediaObjects(countMediaObjects))
{
while (dr.Read())
{
int mediaObjectId = Int32.Parse(dr["MediaObjectId"].ToString(), CultureInfo.InvariantCulture);

// Retrieve the media objects each by each using the cache if possible.
// Don't duplicate the logic of RetrieveMediaObject() here.
IGalleryObject mediaObject = RetrieveMediaObject(mediaObjectId);
if (mediaObject != null)
{
result.Add(mediaObject);
}
}
}
}
finally
{
if (dr != null) dr.Close();
}

return result;
}

The factory then gets called by the Utils method:

Util.cs:
Code:

/// <summary>
/// Gets the newest/latest media objects.
/// </summary>
/// <param name="countMediaObjectd">The count media objectd.</param>
/// <returns>The newest/latest media objects.</returns>
public IGalleryObjectCollection GetLatestMediaObjects(int countMediaObjectd)
{
return Factory.GetLatestMediaObjects(countMediaObjectd);
}

which gets called by the GalleryPage:

GalleryPage.cs:
Code:

/// <summary>
/// Gets the latest media objects.
/// </summary>
/// <param name="countMediaObjects">The count media objects.</param>
/// <returns>The latest media objects.</returns>
public IGalleryObjectCollection GetLatestMediaObjects(int countMediaObjects)
{
return this._util.GetLatestMediaObjects(countMediaObjects);
}


On the UI part I've did mainly what you suggested above by cloning the ThumbnailView control and adding it to the Album page.

As you see in the following album markup the user control is always added to the album markup. The decision if needs to be rendered or not is done within the control not the album page:

Album.aspx:
Code:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="album.ascx.cs" Inherits="GalleryServerPro.Web.gs.pages.album" %>
<%@ Register tagPrefix="ComponentArt" namespace="ComponentArt.Web.UI" assembly="ComponentArt.Web.UI" %>
<%@ Register Src="../controls/albumheader.ascx" TagName="albumheader" TagPrefix="gs" %>
<%@ Register Src="../controls/thumbnailview.ascx" TagName="thumbnailview" TagPrefix="gs" %>
<%@ Register Src="../controls/latestthumbnailview.ascx" TagName="latestthumbnailview" TagPrefix="gs" %>
<gs:albumheader ID="ah" runat="server" EnableInlineEditing="true" />
<asp:PlaceHolder ID="phMessage" runat="server" EnableViewState="False" />
<gs:thumbnailview ID="tv" runat="server" />
<gs:latestthumbnailview ID="latest" runat="server" />


The LatestThumbnailView's decides on load if it needs to be rendered or not with the following code:

Code:

protected void Page_Load(object sender, EventArgs e)
{
var album = this.GalleryPage.GetAlbum();
Visible = (album != null) && (album.IsRootAlbum);
}


Loading / binding the data in that control is done using the method GetLatestMediaObjects() from the GalleryPage. Here is where the hardcoded value "10" is in. This should be replaced by a configuration setting:

Code:

private void BindData()
{
DisplayThumbnails(this.GalleryPage.GetLatestMediaObjects(10));
}


Finally the markup of the control is no rocket science but a clone of the ThumbnailView just without the callback / AJAX stuff:

Code:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="LatestThumbnailview.ascx.cs"
Inherits="GalleryServerPro.Web.Controls.latestthumbnailview" EnableViewState="false" %>
<%@ Register Namespace="ComponentArt.Web.UI" Assembly="ComponentArt.Web.UI" TagPrefix="ComponentArt" %>
<%@ Import Namespace="GalleryServerPro.Business.Interfaces" %>
<asp:PlaceHolder ID="phMsg" runat="server" />
<h3>
Newest media</h3>
<asp:PlaceHolder ID="phPagerTop" runat="server" EnableViewState="false" />
<asp:Repeater ID="rptr" runat="server" EnableViewState="false">
<HeaderTemplate>
<div id="thmbCtnr" class="gsp_floatcontainer">
</HeaderTemplate>
<ItemTemplate>
<div class="<%# GetThumbnailCssClass(Container.DataItem.GetType()) %>">
<div class="op0" style="width: <%# (Convert.ToInt32(DataBinder.Eval(Container.DataItem, "Thumbnail.Width")) + 15).ToString() %>px;
height: <%# (Convert.ToInt32(DataBinder.Eval(Container.DataItem, "Thumbnail.Height")) + 10).ToString() %>px;">
<div class="op1">
<div class="op2">
<div class="sb">
<div class="ib">
<a href="<%# GenerateUrl((IGalleryObject) Container.DataItem) %>" title="<%# GetHovertip((IGalleryObject) Container.DataItem) %>">
<img src="<%# GetThumbnailUrl((IGalleryObject)Container.DataItem) %>" alt="<%# GetHovertip((IGalleryObject) Container.DataItem) %>"
style="width: <%# DataBinder.Eval(Container.DataItem, "Thumbnail.Width").ToString() %>px;
height: <%# DataBinder.Eval(Container.DataItem, "Thumbnail.Height").ToString() %>px;" /></a></div>
</div>
</div>
</div>
</div>
<%# GetGalleryObjectText(Eval("Title").ToString(), Container.DataItem.GetType())%>
</div>
</ItemTemplate>
<FooterTemplate>
</div>
</FooterTemplate>
</asp:Repeater>
<asp:PlaceHolder ID="phPagerBtm" runat="server" EnableViewState="false" />


Hope this explains how I did it. No really big deal yet but quite useful for my gallery visitors looking for the latest images.

It would be very nice if this feature makes it into one of the next releases so I am not on a dead end with my GSP installation but still can upgrade ;-)

What do you think about this?

Cheers,
Marc
Roger Martin
#12 Posted : Monday, 4 January 2010 12:39:37 PM(UTC)
Roger Martin

Rank: Administration

Joined: 3/08/2007(UTC)
Posts: 3,298
Location: Fort Atkinson, WI

Nicely done. Good job of using the existing architecture and API.

I have every intention of doing something like this and it is near the top of the list. I intend to combine it with a new user control that can be added to a page just like the top-level Gallery user control.
Roger Martin
Creator and Lead Developer of Gallery Server Pro
marcd
#13 Posted : Monday, 4 January 2010 9:56:50 PM(UTC)
marcd

Rank: Advanced Member

Joined: 13/02/2009(UTC)
Posts: 53
Location: Zurich, Switzerland

Roger Martin wrote:
I have every intention of doing something like this and it is near the top of the list. I intend to combine it with a new user control that can be added to a page just like the top-level Gallery user control.


sounds good to me but how is the "only-if-rootalbum" check then is done? just within the control? i could think of nearly the same control / feature but with the newest N albums instead of media objects. maybe that could be in mind when designing the new control so both features can be covered at once. ...just a thought ;-)

cheers,
marc
Roger Martin
#14 Posted : Tuesday, 5 January 2010 1:01:02 PM(UTC)
Roger Martin

Rank: Administration

Joined: 3/08/2007(UTC)
Posts: 3,298
Location: Fort Atkinson, WI

That's a good question - haven't figured that out yet, but I will somehow make it possible. (hopefully I don't forget)
Roger Martin
Creator and Lead Developer of Gallery Server Pro
Rss Feed  Atom Feed
Users browsing this topic
Guest
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.