This question has probably been the most covered question in all of DotNetNuke's lifetime but I'm going to ask it here in StackOverflow because I need an answer, a really good one that doesn't make me look the other way. Thanks in advance to all DNN experts.
I've researched many ways of making this work for me and i've seen Michael Washington's solutions (Panels, MultiViews, ...) and Will's (Strohl) blog post on DotNetNuke's personalization engine through setting SkinSrc which is useful, as well as reading through Default.aspx's code which has given me more insight, however, i'm still faced with the problem that calling EditUrl()/NavigateUrl() brings me to a page with a single module in admin skin or a page with nothing respectively.
The specific version is DotNetNuke 6.0.1 (DNN). This Module has 4 other views in addition to the main view which I desire to navigate through sequentially. e.g.
Begin Checkout -> Collection of Delivery Details -> Confim Order
Have you found a solution?
I want to achieve
1) Module loads with other modules around. No module isolation
2) Views in a module that don't Preload e.g. Page_Load in each view gets called when the Module loads up
Help!
Assuming you are asking this as the module developer, the solution is to not use DNN's mechanism for specifying a control. So, you can't use EditUrl or specify the ControlKey in the NavigateURL call (which both generate "ctl=mycontrol" in the URL). Instead you need to have your module display your various controls based on the Query String parameters. So, you'll generally have a control in your module who's primary purpose is to dynamically load other controls based on the query string. So, for instance:
You will start with your control that lists items. You'll have a "Buy Now" button for each item. The hyperlink for each item can be generated by calling
NavigateURL(TabID, "", "View=BeginCheckout", "itemid=" & id, "mid=" & mid)
2.) On the page load of the handler control, it looks to see if anything is specified for the "View" Querystring parameter. If not it displays the listing control, if so, it displays the corresponding control.
Dim controlPath As String
Dim path as String = "~/DesktopModules/MyModule/Controls"
Select Case Request("View")
Case "BeginCheckout"
ControlPath = path + "BeginCheckout.ascx"
Case "DeliveryDetails"
ControlPath = path + "DeliveryDetails.ascx"
Case "ConfirmOrder"
ControlPath = path + "ConfirmOrder.ascx"
Case Else
ControlPath = path + "ItemList.aspx"
End Select
If System.IO.File.Exists(Request.MapPath(controlPath)) Then
placeholder.LoadControl(controlPath)
Else
Throw New Exception("Unable to load selected template. Please go into module settings and select a list and details template.")
End If
Most of the advanced modules for DNN do something along these lines so there's plenty of sample code out there. I would guess some of the core modules do something similar. I adapted the code above from Efficon's Articles module for DotNetNuke.
Related
I am a big advocate of the Page Object Pattern (POP) as defined by the experts at Selenium:
https://code.google.com/p/selenium/wiki/PageObjects
A key view of theirs that I have always followed when using Appium with Java is:
"Methods return other PageObjects"
e.g. LoginPage loginPage = homePage.gotoLoginPage();
I am now trying to following POP using Calabash with Ruby and so have been writing code like this:
e.g. #login_page = #home_page.goto_login_page
However, since Ruby doesn't know what type of object #login_page is or #home_page is, you dont get any of the benefits of intellisense showing what methods are available for a given page.
Anyone know a good way around this?
As much as I appreciate and apply PO design pattern, as much I disagree with returning page object by page object. Page object should be independent and don't need to know about other page objects. Look at two examples:
You test form validation. Click on submit button returns page object which is subsequent in the workflow, but in this case you remain on page with validation errors. Your page object won't know about it and will return the other page.
Page which you get to after clicking a button may differ depending on the context (e.g. from what other page you got to current page). It can lead to having multiple versions of actually same method, which will return different page objects depending on context. This is not good and overcomplicates simple thing.
If you want to return current page object, you can benefit from it e.g. in Java, when you return this at the end of the method. Then you can chain all methods you execute as long as you are on the same page. But when it comes to the question 'how to implement returning different page objects' - answer is simple - 'just don't'. Please note wiki entry you quoted has not been updated for a good while and best practices has evolved since it was originally published.
It seems like you already have your solution. However for others and perhaps also for you the x-platform approach to calabash uses page objects so you could check out that implementation https://github.com/calabash/x-platform-example
An alternative method would be as follows. Not as neat as I would like (given the need to manually create new instances of subsequent pages), but available as an alternative option:
When(/^I buy a movie from the movie page$/) do
movie_page = MoviePage.new
movie_page.buyMovie("Test Movie")
purchase_page = PurchasePage.new
purchase_page.confirmPurchase
end
Found a way of getting this to work after much research and applying well known Java/C#/Obj-c principles to Ruby:
Given(/^I am on the launch page$/) do
#launch_page ||= LaunchPage.new
end
When(/^I open the set alarm time page$/) do
#set_alarm_page = #launch_page.goto_set_alarm_page
end
When(/^I open our apps from the home page$/) do
#launch_page.navigation_toolbar.open_our_apps
end
Then(/^I should see the homepage alarm time is (\d+)$/) do |alarm_time|
alarm_time_actual = #launch_page.get_alarm_time
assert_equal(alarm_time, alarm_time_actual)
end
As long as somewhere on the step definition class you explicitly create a new page object (in the above example: LaunchPage.new), then all subsequent pages will provide intellisense method/property values, since the resulting page types returned will be known by RubyMine.
I'm building a web service for a client that pulls data from the Sitefinity CMS. The problem is they want to pass in a Guid for the service and receive the info about this item. No problem except I only have been able to locate the "live" Guid for one Item (and that was by combing through the HTML in the back end).
I was going to look at the tables in SQL Server but I'm not sure which table to look at. The content items have several tables all related of course and there isn't any documentation on how to look at this. I can find plenty of documentation on querying the master Guid, but no place to find it.
Oh, and these are custom content types built by the Module Builder.
Any Help would be SOOOOO appreciated!
var master = DynamicModuleManager.GetManager().Lifecycle.GetMaster(<liveGuidHere>);
One of the biggest consumers of Sitefinity webservices is Sitefinity. The best place to start looking for that guid is to take a look at what web service calls are being made when you pull up your custom content item list in the backend. I used the chrome developer tools and check in the network tab.
One I found for a stores module made with module builder was something to the effect of http://www.testsite.com/Sitefinity/Services/DynamicModules/Data.svc/?managerType=Telerik.Sitefinity.DynamicModules.DynamicModuleManager&providerName=OpenAccessProvider&itemType=Telerik.Sitefinity.DynamicTypes.Model.Stores.Store&provider=OpenAccessProvider&sortExpression=LastModified%20DESC&skip=0&take=50
The json this returns is a list of all the masters with their ids (note in the list that the content items all have have a status of 0) http://www.sitefinity.com/documentation/documentationarticles/developers-guide/sitefinity-essentials/modules/content-lifecycle
When you go to Administration / Module Builder / Your Module, you will see a link to the API on the top right corner.
This link goes to a page full of API examples for your particular module which is kind of cool.
Basically you would have to find your item first using LINQ and the GetValue extension method.
Once you have the item you can get its ID or any other property.
using Telerik.Sitefinity.Utilities.TypeConverters;
using Telerik.Sitefinity.DynamicModules;
using Telerik.Sitefinity.Model;
....
var mgr = DynamicModuleManager.GetManager();
var countrymasters = from ctry in mgr.GetDataItems(TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.Destinations.Destination"))
where ctry.GetValue<string>("culture") == siteid &&
(ctry.Status == Telerik.Sitefinity.GenericContent.Model.ContentLifecycleStatus.Live && ctry.Visible == true)
select new
{
airport_cd = ctry.GetValue<string>("airport_cd"),
country_master_cd = ctry.GetValue<string>("country_master_cd")
};
As the title suggests my question is pretty simple.
Is there a way to count the total number of active module instances of a specific type/kind in Joomla (with a specific module name)?
I know how to count modules in a specific module position using JModuleHelper::getModules, but that is not what I want.
I simply need to count all active modules instances of a specific type/kind.
Does anyone know how to do this (without having to do a manual MySQL query)?
I do not know if there is an official joomla way, but you can do it by having an sql query looking at
#__modules
table.
Check out this table and you will find out how easy it is.
An example sql would be:
select count(id) from #__modules where module = 'mod_login'
As far as i know there is no joomla method for this. I would recommend (if it has to be done) either
using a crawler to go through all pages of the site counting the instances.
or using a script which goes through the template php files and the database to find all active instances.
Both these methods might not be 100% reliable due to unexpected circumstances (like module being included in article or module included only after a button is clicked on) but could work if you know your site well enough.
Unfortunately there does not seem to be such a function in Joomla.
In my case I needed this to tell me whether or not a instances of this module was > 0 or not.. and my alternative solution was to simply make a module-specific function and then in the module php file check if function is already loaded.
Context:
I'm trying to make reusable step definitions that click on page objects on the current page,
e.g. (cucumber step def follows):
When(/^the user clicks the "([^"]*)" button$/) do |button|
click_button = button.downcase.gsub(" ","_")
#current_page #somehow get current page object on this line
#current_page.click_button
end
Problem statement:
I can't find anything that returns the current page object.
An explanation for why the obvious solution didn't work:
I thought #current_page was already there as something I could use. I looked in the source code for page object, and the variable #current_page does exist. Not sure how to use it if I can...
BTW, in this case, I have a bunch of testers that can write Gherkin but not necessarily step definitions. We are trying to rapidly finish a bunch of regression tests for an in house app with an unchanging interface.
This is somewhat at odds with what page-object is trying to provide.
Page object attempts to provide well named actions for interacting with a specific page. If you are wanting to make something that works in general against any page, it will be much easier to write it with watir-webdriver directly.
That said, I agree that a specification based heavily on implementation like that is likely to change. I also would add that it doesn't add much value. I would only continue down this path if you understand and accept that you are using cucumber as a test templating tool instead of a requirements communication tool.
As Justin Ko mentioned, #current_page gets set when you call the on or visit methods. Its not a good idea to lump something that changes the page object in a step that performs a specific action (in this case clicking a button). You might want a different step that indicates the behavior of the application, such as
the application lands on the <your page> page
Then you're can use the name of the page object class to load #current_page via the on method in that step definition. This also gives the benifit (or curse of having your step having more lower level details) of indicating expected page navigation behavior.
I have some views that uses #UserName in the selection formula. For working that, the view must be "Shared, Desktop Private on 1st use". That is no problem.
But this views are going to be redesigned quiet often.
As this is a bunch of views it is very uncomfortable for the user to delete each of this views to recreate from scratch with design changes.
I try different things to get that done with an agent but no one is fool-proof and give some strange results (sometimes even do not update the design).
Best result so far is to delete the icon from the workspace and open the application again. That works (until now) always. But this is so annoying for end users to reopen the app from the (deep leveled) server folders.
Any other method to update the design of "private on 1st use" views ?
As you noticed, private views are a pain to maintain. Why not go a different way to solve your problem?
Create a categorized view, where the first, categorized column contains the field you compare the username in your current solution to.
Than embed that view into a form as a "single category embedded view" and use #username as the category.
Presto. Now you have a view that only shows documents for the current user and you can change the design whenever you like.
Mick Moignard has a good article on that topic online: Dynamic view filtering in Notes.
See also the Lotus Domino Designer Help, Topic "To show a single category in embedded views"
I have tried to solve the same problem and ended up doing two things - (1) automatically send the user an email with a link to the database and ask them to remove the database icon so that the private views get deleted and (2) alert the user when the design of a private view has changed.
The first part was fairly simple - I wrote a LotusScript function that would send the current user an email message containing a link to the current database (the one that contains the private views), along with some meaningful text and database information. All the user had to do then was exit the database, remove the database icon, open the email they just received and open the database again using the link. No need to navigate the server folders or wonder which server to go to. This can be used on its own, e.g. in a button, but I ended up combining it with something a little more tricky.
The second part was devising a way to alert the user that the design of the view they are opening is outdated. The tricky part was detecting that the design of the view has changed. What made this possible was what actually caused the problem in the first place - the fact that Notes caches the private view. When caching the private view, Notes also caches constants that the script in the view events refer to, that are part of LotusScript libraries the view uses.
Here's a description of the design I used:
Let the view use shared script library, PrivateViewsCode.
In PrivateViewsCode's (Declarations) declare Const DESIGN_VERSION = "1.0".
In PrivateViewsCode declare function myQueryopen. One of the parameters myQueryopen receives is string designVersion.
In the private view's Queryopen event call myQueryopen, passing DESIGN_VERSION to designVersion. Since this code is in the view that is cached, DESIGN_VERSION will contain the constant value as it were in the moment the view design was cached (when the user first opened it), in this case - "1.0".
In myQueryopen compare designVersion to DESIGN_VERSION.
Dim designChanged As Integer
designChanged = (designVersion <> DESIGN_VERSION)
Since myQueryopen is part of PrivateViewsCode script library, here you actually compare the DESIGN_VERSION (as cached in the private view and then passed to myQueryopen) to DESIGN_VERSION from PrivateViewsCode, which is always current.
The only thing left is to be sure to recompile the views (Tools\Recompile all LotusScript) after changing DESIGN_VERSION.
I hope this explains the design, here is how it works:
After making changes to private views design you change the version:
DESIGN_VERSION = "1.1"
Recompile all LotusScript.
Refresh the database design.
Users open any private view that uses this functionality.
They get a message saying they will receive link to the database and that they have to remove the icon from the workspace and open it again using the provided link.
The user closes the database and removes the icon - private views are deleted.
The user opens the database link in the email, the next time they open one of the private views, the new design is cached along with the new value of DESIGN_VERSION (here, "1.1").
The comparison (designVersion <> DESIGN_VERSION) now yields false. Everything is back to normal until the next update.
Ken's way of handling this has the major advantage of not involving the users at all. This wasn't an option for me because of the frequency with which I made changes to the views (the application was just deployed and I had many requests for changes to the views) as well as the big number of private views in the application.
(Edit)
I assumed you had a specific reason to use private views, but I used the "Show Single Category" in an embedded view (just as leyrer suggests) ever since it became available and was quite happy with it. If you see any limitations to using the "Show Single Category" option, I'll try to help you with that.
I found a way that moves the pain from the end user to the developer. I designed the navigation to use outlines so I can control where the user goes when they navigate to a view. Notes outline entries can be changed without the user needing to go through the delete-icon-then-reopen-database hassle.
When I need to update the design of the private view, I rename it as well and also update the reference to it in the notes outline entry. At the users desktop, when they next open the database, a new private view will be created for them. Most (or all) of my users never noticed anything, at least they never mentioned it!
The process is fairly easy for the developed but also fairly easy to forget. Also, the user's workspace will end up having a lot of references to old unused private views, which if they are large in size might become a problem down the line. If you change the view twenty times, or change twenty views, for example, it may be time to delete the icon to clear them out. For me the changes were rare enough for this not to matter.
The solution to your dilemma is not too hard to solve, but a little tedious. There is a technote on simply removing private views programmatically. It is a common design issue for developers.
I have had to take the following approach to manage multiple private views which were all going through multiple versions at any one time.
The secret is to do a check on the DatabaseOpen event, as it's a view held on the local client so you need to do this through user's UI activity. As long as your Lotus Notes client fleet is at running version 6.5.x you could try the following. To be concise, I have outlined what you need to do.
Name your private view "yourPrivateViewName_1.0|yourPrivateViewName"
Note the use of an alias. This is so you can reference the view in an outline or code, no matter how many versions you use.
This can also be a multi-valued field if you have more than one private view to manage.
Create a database profile document that has a field with the current private view name, eg "youPrivateViewName_1.1"
On DatabaseOpen loop through the views, finding the private view(s) then compare the name to the one in the database profile. The naming convention is designed to make it possible to do a version check. If the versions don't match, remove the view. When the user opens that view the next time it should grab the current version you have released.
There are other ways as well, like checking the timestamps on the private view and the template, but it still requires a way to single out the private view. But I found this way easy enough to manage.
Thank you all !
I finally ended up with the following:
Create an Agent running from menus that close the database
Sub Initialize
Dim s As New NotesSession
s.SetEnvironmentVar "remove-"+s.CurrentDatabase.ReplicaID,"1"
Dim ws As New NotesUIWorkspace
ws.CurrentDatabase.Close
End Sub
In the database close event mail a database link and send keys to remove from workspace
Declare Sub keybd_event Lib "user32.dll" (Byval bVk As Integer, Byval
bScan As Integer, Byval dwFlags As Integer,Byval dwExtraInfo As Integer)
Sub Queryclose(Source As Notesuidatabase, Continue As Variant)
Dim s As New NotesSession
x = s.GetEnvironmentString("remove-"+s.CurrentDatabase.ReplicaID)
s.SetEnvironmentVar "remove-"+s.CurrentDatabase.ReplicaID,""
If x="" Then Exit Sub
Dim ws As New NotesUIWorkspace
Call ws.AddDatabase( s.CurrentDatabase.Server,s.CurrentDatabase.FilePath)
Dim m As New NotesDocument(s.CurrentDatabase)
m.From = s.CurrentDatabase.Title
m.SendTo = s.CommonUserName
m.Subject = "Link to open " + s.CurrentDatabase.Title
Dim rt As New NotesRichTextItem(m,"Body")
rt.AppendText s.CurrentDatabase.Title
rt.AppendText " -> "
rt.AppendDocLink s.CurrentDatabase,"Open Application"
m.Send False
Delete m
keybd_event &h2e,0,0,0 ' Del key down
keybd_event &h2e,0,2,0 ' Del key up
keybd_event &h0D,0,0,0 ' Y key down
keybd_event &h0D,0,2,0 ' Y key up
End Sub
(You all got your upvotes but a i mark as answer for the lowest rep. points user.)