I've got a page extension which can apply a colour to a page. This is accessed via a template tag which checks for an attribute of each page, and at the moment this is just running a Page.objects.filter() call which is obviously hammering the database because this is called for every nav_node in a menu.
Does the Page model have a cache I can run the reverse_id filter on? My extension object gets cached, but when trying to apply this filter to a menu item I need to try to establish if the nav_node is a Page as you see below so I have to go straight to the objects (or does that call the cache first?).
#register.filter(name='colour')
def colour(nav_node):
"""
Filter receives a CMS menu NavigationNode. We cannot assume this is a Page.
:param nav_node: a node from the cms menu
:type nav_node: menus.base.NavigationNode
:return: colour associated with the Node or None
:rtype: str
"""
pages = Page.objects.filter(reverse_id=nav_node.attr['reverse_id'])[0:2]
page = next((x for x in pages if hasattr(x, 'pagecolourextension')), None)
if page is None:
colour = ''
else:
colour = page.pagecolourextension.page_colour
return colour
I can't see anything on the Page model leading to a page cache, but on the manager there are plenty of calls to invalidate the page cache. How can you run a filter on the cached pages?
I decided the best way to go about this was to create my own cache key for CMS Pages which I can use to access my page extensions, so I've moved the logic which queries the db;
pages = Page.objects.filter(reverse_id=nav_node.attr['reverse_id'])[0:2]
page = next((x for x in pages if hasattr(x, 'pagecolourextension')), None)
To put this into a if cache.get(key): type function so I have pages with a reverse_id accessible via my cache methods. This is great because it should enable me to cache page's and then for any of my page extensions call the cache and equally trigger signals based on changed fields.
Related
I was asked to capture the analytics on a website. The website is made up of 5 web pages, but I now realize that the domain is the same and the only thing that changes is the URL fragment, i.e. www.domain.com#a, www.domain.com#b. The only info that comes through to GA is the domain and it does not include the URL fragments. The tracking code I'm using is Tealium and the data is being sent back to Google Analytics. How can I set this up so that i can see the entire URL in GA including the URL fragments?
So, from Tealium's perspective we need to trigger a view event when a new fragment is loaded (if I am understanding this correctly).
If we assume that the fragment change occurs on a link click then we need to trigger the view event when the link click occurs.
From the GA perspective, we need to trigger a view that captures the new information. For a view this is likely to be location, path and title.
Therefore, we need Tealium to construct the new data points and then pass them in a view event to GA.
The simplest way to do this in Tealium (all things being equal) is via a jQuery onHandler Extension
The jQuery extension requires the following information:
jQuery selector (or selectors) to pay attention to
"Trigger On" event type (this will be Click in this example)
Tracking event type to run (View event in this case)
Variable & values to set
Tealium jQuery onHandler extension config
note it's always a good idea to set a condition on your jQuery extensions so that they only run when needed instead of all the time and everywhere
In this extension, I have set the following:
jQuery Selector: '#MyID_1, #MyID_2, #MyID_3' -- yes you can pass a list of selectors or nearly any other valid jQuery selector statement
Trigger On: 'click'
Tracking Event: 'view'
3 Variables:
a. 'page_name' : $(this).text(); //get the link text
b. 'my_url' : utag.data['dom.url']+$(this).attr('href') //building the full URL including the fragment
//utag.data['dom.url'] is a variable/datapoint that Tealium automatically generates
c. my_path : utag.data['dom.pathname']+$(this).attr('href'); //building the path
//utag.data['dom.pathname'] is a variable/datapoint that Tealium automatically generates
NOTE: make sure to set the type for each these to "JS Code" otherwise your JavaScript will be quoted out as a string.
Why these three variables? As I understand GA, these are the values it would expect for a new page view -- location/URL, path, and Title so we are constructing those values in the extension to pass them to GA on the view event.
Now, we just need to map these new variables to GA.
my_path gets mapped to page in the GA mapping toolbox
page_name gets mapped to title
location isn't a default option in the mapping toolbox so we need to add a custom destination variable called location and map my_url to it.
custom variable mapping for GA
That's how you do it from within Tealium and minimal coding. If for some reason you don't want to / can't do it inside of Tealium, this provides us with a very nice template for a custom function to add to our codebase:
`$(document.body).on('click', '#altID', function(){
utag.view({
"page_name": $(this).text(),
"my_url": utag.data['dom.url'] + $(this).attr('href'),
"my_path": utag.data['dom.pathname'] + $(this).attr('href')
})
})`
See both in action over here at CodePen.
Can I save the page status if I moved to new page?
I have a map and some objects on the map. I want if map is loaded, that all state saving if i moved new page and then I come back. That's it high-loaded process (+ loading image again). Use lealetjs
Thanks!
I solved my problem as follows:
I change app architecture - I add two tabs (list elements page and map with markers). And when I opened map page use tabs - page loaded and it's Ok!
Explanation of work ionic:
If you use navCtrl.pop() - current page will be deleted from memory. But If you can not use tabs - use navCtrl.push() new before page. And when user will want to return before page - navCtrl.pop() - delete current page, but before page will be cached.
That is, from the user's point of view - it's back is already on the previous page, and from the point of view of the programmer - a new same page is being created.
And if user wants to move to before->before page, use navCtrl.popTo(index of the desired page - you can use this.navCtrl.popTo(this.navCtrl.getByIndex([yourPageNumber]));
I have a folderish dexterity content type and I have an event subscriber. When the content type is created, I create a Collection, which shows the children in the container according to several parameters. After the collection is created, I try to set the default page of the container to the collection.
def myContainerAdded(my_container, event):
#get container
#set advanced query for collection
#create collection with api.create
my_container.setDefaultPage(new_collection.id)
The subscriber in configure.zcml
<subscriber
for="my.product.my_container.IMyContainer
zope.lifecycleevent.interfaces.IObjectAddedEvent"
handler=".events.myContainerAdded" />
Unfortunately, the default page is not being fully set. It just shows the container page, but the Collection is selected under the 'Display' drop down.
If I click "Change content item as default view" and select the collection, it does change the default page to the collection.
Earlier, I was using a "setuphandler" to setup a folder structure (as opposed to an add event), and setDefaultPage was working. Am I forgetting a step since I'm attempting this through an event?
I am using plone.4.3.
Edit: I also tried:
my_container.default_page = new_collection.id
Edit:
I found something interesting. I temporarily commented out the code related to the collection in the event subscriber. I manually added the collection to the container object and then set the default page of the container to the collection. The container's default page was the collection.
Maybe something isn't getting indexed right?
In fact everything went well, it's just that after creating a Dexterity-based content-type, one will land on the default-view's URL, meaning '/view' is appended to the item's URL, which is an alias to the default-view-method and here resolves to the 'folder_listing'-template.
To overcome this quickly, you can add a redirect to the object's URL in the subscriber's method, without any view-name appended to the URL:
event.REQUEST.RESPONSE.redirect(my_container.absolute_url())
Overview
We have an in house CMS that we've recently added multilingual support to. The CMS allows dragging/dropping of various panels (.net controls) and some panels show dynamic content entered via a rich text editor. Also, some fields are multilingual so some panel content will change according to the current language.
Ideally we want to add the language to the URL. So /contact-us becomes /en/contact-us.
Our main handler will then set the language and the all panels will show relevant copy.
Goal
So, ideally we'd like to be able to:
Process the page server side after it's been built by our main page assembler (eg in PreRender)
Parse the built page or recurse the control tree to update ALL internal links
Prepend a lanauge code to all internal links on the page. (easy enough once we know where they all are)
NB: Some links will by in .net HyperLink controls but others will be <a> tags entered via a Rich Text Editor.
Stuff I've looked at
I've skimmed google but haven't found anything that seems to match our needs:
Html Agility Pack - can be used to take a URL and parse for links. But I'm guessing this can't be used say in Pre_Render of our main page builder. Ideal for scraping I suppose.
Various JS solutions - locate links and update. Very easy but I'm wary of using JS for updating URLs client side.
All suggestions welcome :)
So, There will be dynamic content and static content. And the CMS users should be able to edit both of them. You should have a Language DB table, and for instance; For "about us" page, There should be about-us EN, about-us DE, about-us FR rows in other table.
And you should have another table for static content. For instance for contacy us form. There are static texts on contact forms. Name, e-mail,message etc.
This can be done by overriding Page.Render() as follows:
protected override void Render(HtmlTextWriter htmlWriter)
{
StringBuilder ThisSB = new StringBuilder();
StringWriter ThisSW = new StringWriter(ThisSB);
HtmlTextWriter RenderedPage = new HtmlTextWriter(ThisSW);
// pass our writer to base.Render to generate page output
base.Render(RenderedPage);
// get rendered page as a string
string PageResult = ThisSB.ToString();
// modify the page
string ModifiedPage = UpdatePage(PageResult);
// write modified page to client
htmlWriter.Write(ModifiedPage);
}
The method UpdatePage can manipulate the page as a string in any way you wish - in our case we use find and update all links and local file paths.
I have an browser based application built with Flash Builder (actually Flex 3.5) with a Java backend. The application works well. It has a default login page and users can always login and view products by typing the product id in an input field to display product and other info.
I will like to modify this application in such a way that a product page can be viewed by just including the product id in the url something like www.myserver.com/?product_id=1234577
I am completely at lost on how to implement this and not even sure if this is possible at all.
Yes, this is definitely possible.
The key details are from Pass url parameters to a swf (flash) movie:
Look at loaderInfo.parameters["product_id"] in your Flex code; as your application initializes, hook into your current logic that brings up info when you type in a product ID.
You may use this approach . You can pass parameters like (if embedded in jsp page)
var flashvarsWF = {};
flashvarsWF.product_id= '<%=productId%>';
And you can pass this flashvarsWF in
swfobject.embedSWF()
In flex main application(mxml), you can receive this as
var pId:String = this.parameters.productId;