8/30/2009

Displaying a “no search results” message when no search results are found

In earlier (4.x) DNN versions, when you make a search and it yields no results you are presented with an empty search results page – without any message. It’s silly, but nobody ever included this as a feature.

 

Thanks to this post, I found a way to include a “no search results” message. Or course, there are plenty of ways to do that, but I think this is the fastest. You’ll have to edit the admin/search/searchresults.ascx file as follows:

 

First, find this line and add what’s written in big, bold letters:

 

<asp:HyperLink id=”lnkTitle” runat=”server” Name=”result” CssClass=”SubHead” NavigateUrl=’<%# FormatURL(DataBinder.Eval(Container.DataItem,”TabId”),
DataBinder.Eval(Container.DataItem,”Guid”)) %>’ Text=’<%# DataBinder.Eval(Container.DataItem, “Title”) %>’>
</asp:HyperLink>

 

Then add the following code directly under the last line of the file:

 

<div id=”NoResults”>
<h3 class=”red” style=”text-align:center”>No Search Results Found</h3>
</div>
<script language =”Javascript”>
var search;
search = document.getElementsByName(”result”);

if (search.length == 0) {
document.getElementById(”NoResults”).style.display=’block’;
}
else {
document.getElementById(”NoResults”).style.display=’none’; 
}
</script>

 

Change the “No Search Results Found” string to whatever you like and you’ll have your “no results” message when your search yields nothing. Of course, you can also change the h3 tag with whatever you like, even include an image.

 

I don’t know what’s going on with 5.x versions since I haven’t tried it yet in one, but I think it’s still an interesting tweak for 4.x versions.

 

EDIT: This may not work if you leave the single and double quotes as they are in the code above. Better paste the code to Notepad first. Sorry about that, but I didn’t have the time to replace. (Live Writer can be very unfriendly sometimes :) )

Read more...

4/27/2009

DnnGallery.net – a place to showcase your DNN sites

One of the questions I have always found hard to answer is “ok, but show me some ‘wow’ sites made with DotNetNuke”. I always had a hard time finding some sites till I read a post about www.dnngallery.net at the DotNetNuke forums.I think it’s pretty interesting, provided that the “Showcase” section at the official DotNetNuke site is dead and that there is no other place (none that I know of, at least) where one can see and rate some worthy DNN sites.

 

DnnGallery allows you to submit your DNN site and lets other users rate it. You will find some interesting implementations there, let’s hope that more DNN publishers participate in the future.

Read more...

4/21/2009

UDT 03.05.01 and incorrect filtering of script in text/html fields

Those of you using the latest version of the old User Defined Table module (which is to be replaced by the Form and List module in DNN 5.x) may have noticed an annoying bug that makes the UDT module insist on filtering out script, object and embed tags even when you have specifically specified that you don’t want it to.

 

What does this mean? It means that you can’t embed YouTube videos, for example, because UDT will filter out the embed code’s tags.

 

When does it happen? Well, fortunately it doesn’t happen when you’re admin or host. But it does happen if you’ve given other users edit rights on UDT data. Any user that is not Admin or Host cannot write these tags in the HTML view of a Text/HTML field inside a User Defined Table. They are just filtered out, even when the relevant setting is unchecked.

 

To fix that, you’ll need to download the code for UDT 03.05.01. The problem lies in file EditControls.vb, line 52:

 

If ParentModule.Settings.ContainsKey(SettingName.ForceInputFiltering) Then
               
inputFilterScript = Not isAdmin
               
inputFilterTags = isAnonymous
End If

 

The “if” clause in line 52 just checks whether the setting exists, not its value. To fix that you need to make the code in line 52 as follows:

 

If ParentModule.Settings.ContainsKey(SettingName.ForceInputFiltering) AndAlso ParentModule.Settings(SettingName.ForceInputFiltering).Equals("True") Then
               
inputFilterScript = Not isAdmin
               
inputFilterTags = isAnonymous
End If

 

(I apologise for the line breaks, please consider that the IF clause should be in a single line)

 

What I’ve done is that I have added a second condition that actually checks the VALUE of the setting and applies the rule only if it’s true.

 

You can compile the code with that change and just replace the old dll file with the newly-compiled one in dotnetnuke’s Bin folder.

 

Please let me know if you’ve been having trouble with this, I’ve already got a compiled dll so I could send it to anyone who’s not into code much – although, as always, I must insist that you always try those things at your own risk!

.

Read more...

4/03/2009

Replacing default module titles in search results with the corresponding tab’s title

How many times has it happened to you? You put some Text/HTML module here, a Links module there, maybe a third-party module and you forget to change its title, mostly because you’re using a container that doesn’t utilize it, or for any other reason.

 

This can lead to ugly search results, since DNN’s indexer stores the module’s title in the SearchItem table and uses it as the title for each one of your search results.

 

On the other hand, you’ve got some module titles you’ve explicitly set and you need to preserve for your search results. So, you’ve only got to replace the DEFAULT titles with something – in my script, I chose to replace them with the corresponding tab’s title, but you could alter it and make it display anything – or even delete the record if you like.

 

So here’s a trigger that checks whether the row being written in the SearchItem table is for a module having the default title, and if so, changes the title to the corresponding tab’s title.

 

CREATE TRIGGER tr_FixSearchItemTitle 
  
ON  dbo.SearchItem
  
AFTER INSERT,UPDATE
AS 
BEGIN
   
-- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    
--These three variables will come from the
--searchitem table.
declare @searchitemid int
declare @moduleid int
declare @title nvarchar(200)

--These two will come from the 
--modules table.
declare @moduletitle nvarchar(200)
declare @moduledefid int

--This will come from the 
--moduledefinitions table
declare @friendlyname nvarchar(200)

--This will come from the
--tabs table
declare @tabtitle nvarchar(200)

--Get inserted values
select 
     
@searchitemid = searchitemid
   
, @title = title
   
, @moduleid = moduleid 
from 
   
inserted 

--Find moduletitle and definition id of the 
--module being inserted in searchitems table.
select 
     
@moduletitle = moduletitle
   
, @moduledefid=moduledefid 
from 
   
modules 
where 
   
moduleid = @moduleid

--Find the friendly name from the
--moduledefinitions table
select 
   
@friendlyname = friendlyname 
from 
   
moduledefinitions 
where 
   
moduledefid = @moduledefid

--If the title of the module in the searchitem table
--is equal to the module definition's friendly name
--then we can safely suppose that the module has 
--the default title.
if @friendlyname = @title 
begin
    
   
--Get the tab's title
    select 
       
@tabtitle = title 
   
from 
       
tabs 
   
where tabid in 
       
(
       
--If we have multiple instances
        --of modules in several pages,
        --just get the first page. I know,
        --this might be ugly but I've not found
        --any other way.
        select 
           
top 1 (tabid) 
       
from 
           
tabmodules 
       
where 
           
moduleid = @moduleid
       
)

--Replace the default title with the page's title.
update 
   
searchitem 
set 
   
title = @tabtitle 
where 
   
searchitemid = @searchitemid

end

END
GO

 

This trigger checks each entry in the SearchItem table at the time it’s inserted or updated and determines whether the module title being inserted is a default title. It achieves that by comparing the module’s title with the FriendlyName field of the ModuleDefinitions table – all core modules and all third-party modules I know use this value as the default title. This means the trigger will probably work with any combination of modules you’ve installed in your site.

 

There’s a catch, though: If you have the same module instance (not the same module, the exact same instance – that means you’ve used the “add existing module” option) in more than one page, it’ll get only one title for it – that is, if you’ve “added an existing module” to several pages, each search result that corresponds to such a module may have the wrong title – no problem if you’re not using multiple instances of modules.

 

Another catch is that you have to have recursive triggers disabled for your database, or this will execute forever – it will run itself again and again since it alters a newly inserted or updated record.

 

In order to see how this trigger handle things, you should delete everything from your SearchItem table and then do a reindex via the Host->Search Admin page, or else the trigger will run only for new or updated entries.

 

As always, use at your own risk!

Read more...

1/16/2009

Using the PortalSettings class in containers

It’s simple, but useful: If you try to use the PortalSettings class in code you have added to a container’s  .ascx file, you’ll find out that you can’t. The PortalSettings shared class is only directly accessible from skins.

 

That’s dissapointing, especially when you need to grab things like, for example, the current tab id (PortalSettings.ActiveTab.TabId) inside a container for some reeson.

 

The solution to this is to grab your PortalSettings contents from the HttpContext and use it like this:

 

<script runat="server"> 

Dim _portalSettings As PortalSettings 
_portalSettings = CType( _
   
HttpContext.Current.Items("PortalSettings") _
   
, PortalSettings)

</script>

 

In order to get, for example, the current tab id from your container, you can now use _portalSettings.ActiveTab.Tabid.

Read more...

12/05/2008

How to enable - disable caching programmatically and on-demand

Sometimes, when you're doing something programmatically, like moving tabs around, you really don't want caching in your way in any form, since there's a great danger it'll affect the outcome. For some reason, programmatically clearing the cache may not be enough - you just don't need any caching around when you do certain stuff, and you don't want to oblige any host user to manually clear the cache. Here's a really simple way to disable caching programmatically.

 

 

'Get the initial caching level
'from the HostSettings arraylist 
'(this is the easiest way)
Dim initialCachingLevel As String
initialCachingLevel = _
   
HostSettings.Item("PerformanceSetting").ToString

'Disable caching
Dim hc As New Entities.Host.HostSettingsController
hc.UpdateHostSetting("PerformanceSetting", "0")

'Do your stuff here

'Enable caching with
'the initial caching level
hc.UpdateHostSetting("PerformanceSetting", initialCachingLevel)

 

What I'm doing in the bit of code above is disable caching temporarily to do what I have to do, then return it to its previous state. That's equivalent to going to Host Settings-Performance, from the Host menu, change the caching level, click "update", do any job I have to do and then get back to the Host menu and return caching to its previous value.

 

The caching level is defined by the "PerformanceSetting" Host property which can take string values ranged from "0" to "3" representing different levels of caching:

 

0 - No caching

1 - Light caching

2 - Moderate caching

3 - Heavy caching

 

Some notes:

 

You can get the current caching level from the HostSettingsController too, but it's a bit more fussy since the GetHostSetting method returns an IDataReader. Since the Host's settings get copied to the publicly-available HostSettings hashtable, I thought it's easier to obtain the current setting from there.

 

Changing the value in the HostSettings hashtable will NOT affect your caching. You've got to use HostSettingsController.UpdateHostSetting.

 

You may also want to clear any cache left before you start doing your stuff, it helps in some cases. In this case, the DataCache class may prove very useful. Here's what you can do (you can choose not to execute some of these lines, depending on your needs):

 

DataCache.ClearTabsCache(0)
DataCache.ClearPortalCache(0, True)
DataCache.ClearHostCache(True)
DataCache.ClearModuleCache()
DataCache.ClearTabPermissionsCache(0)
DataCache.ClearUserCache( _
       
0, _
       
UserController.GetCurrentUserInfo().Username)

 

 

Some of the above statements may overlap, in the sense that they're actually subsets of other statements. For example, ClearHostCache() is considered equivalent to the Clear Cache option that exists in the Host Settings page. I personally prefer to issue ALL those statements, even if they overlap.

 

The DataCache class has some more methods but I think those mentioned here are enough to give you a good start. You'll probably find out the rest yourself, in an as-needed basis.

 

The above code applies only to portal 0. Whenever you see a boolean parameter there, it's indicating "cascade" cache clearing, which I always want set to true. Also, the ClearUserCache() method needs the currently logged on user's name, which I get by using UserController.GetCurrentUserInfo() which returns a UserInfo object containing, among others, the user's name.

Read more...

11/28/2008

Resolving "fileid=xxx" field values to actual file paths

Following a previous article of mine, The dbo.tabs.IconFile field issue, I would like to share an easy way to resolve any field that holds values of the type "FileID=xxx" (where xxx is the primary key of a record in the Files table) into the actual file path. This is especially useful when you deal with the IconFile field in the Tabs table, as well as with fields of type Image in a User Defined Table, and probably in a lot more places too.

 

I have created a UDF (User Defined Function) which accepts a string value and looks whether it's of type "FileID=xxx". If it is, it constructs the full path (including the portal number) and returns that, otherwise it just returns the initial string with no modification at all. You can use this scalar-valued function inline, in your own SELECT statements, like this:

 

EXAMPLE

SELECT 
tabid, 
tabname, 
dbo.ResolveFileField(iconfile) 
FROM tabs 

 

CODE

CREATE FUNCTION 
dbo.ResolveFileField
(
   
@file varchar(1000)
)
RETURNS varchar(1000)
AS
BEGIN
    
declare @retval varchar(1000)
declare @portalid int

if patindex ('FileID=%', @file) >0

begin

   
declare @fileid int
   
set @fileid = 
       
convert(
               
int, 
               
replace
                   
(
                   
@file
                   
, 'fileid='
                   
, ''
                   
)
               
)   

   
select 
       
@retval = 
            'Portals/' 
           
+ convert
                   
(
                     
varchar(10)
                   
, files.portalid
                   
) 
           
+ '/' 
           
+ folders.folderpath 
           
+ files.filename 
   
from 
       
files
   
left outer join folders
   
on files.folderid = folders.folderid
   
where 
       
files.fileid=@fileid
    
end

else

begin
   
set @retval = @file
end

return @retval

END
GO

Read more...

Recent Comments

Free DotNetNuke Stuff

Free DotNet Videos

  © Blogger template The Professional Template by Ourblogtemplates.com 2008

Back to TOP