Webcenter Sites : Vanity URLs for images or PDF - vanity-url

I'm working with Webcenter Sites 12.2.1 and I have a question about templating for medias with vanity URLs.
My users would like to have vanity URLs for some Medias like PDFs or Images or such blobs. I'm able to do so for text based attributes such as javascripts or css but for blob based attributes I'm a bit stuck. The point is that for doing vanity URLs for an asset I have to use a template. In the template if I have to display a text there is no problem. For a blob I can get the attribute but if I want to stream the result in as template without calling the blob server URL I don't get anything usable.
Here is the code of the template that I use:
<%#page import="java.io.InputStream"%>
<%#page import="java.io.FileInputStream"%>
<%#page import="java.io.File"%>
<%# page import="com.fatwire.system.*"%>
<%# page import="com.fatwire.assetapi.data.*"%>
<%# page import="com.fatwire.assetapi.query.*"%>
<%# page import="java.util.*"%>
<%# page import="com.openmarket.xcelerate.asset.*"%>
<%# taglib prefix="cs" uri="futuretense_cs/ftcs1_0.tld"%>
<%# taglib prefix="ics" uri="futuretense_cs/ics.tld"%>
<%# taglib prefix="fragment" uri="futuretense_cs/fragment.tld"%>
<%# taglib prefix="render" uri="futuretense_cs/render.tld"%>
<%# taglib prefix="asset" uri="futuretense_cs/asset.tld"%>
<cs:ftcs>
<%
Session ses = SessionFactory.getSession();
AssetDataManager mgr =(AssetDataManager) ses.getManager( AssetDataManager.class.getName() );
AssetId id = new AssetIdImpl( "Content_R",new Long(ics.GetVar("cid")));
List attrNames = new ArrayList();
attrNames.add( "imagefile" );
AssetData data = mgr.readAttributes( id, attrNames );
AttributeData attrDataSource = data.getAttributeData( "imagefile" );
BlobObject fileObj = (BlobObject)attrDataSource.getData();
File file = new File(fileObj.getFoldername() + fileObj.getFilename());
InputStream in = new FileInputStream(file);
byte[] bytes = new byte[2048];
int bytesRead;
ServletOutputStream out2 = response.getOutputStream();
while ((bytesRead = in.read(bytes)) != -1) {
out2.write(bytes, 0, bytesRead);
}
in.close();
%>
</cs:ftcs>
I've already tried a workaround : redirecting to the blob server but the problem is that then I can't use urls directly as for images < img src="/prettyUrl" > with a redirect doesn't work.
Did anyone try to do so ?

Found a solution via the Oracle Community : I have to use a controller.
An example is already given in the sample site application
http://<>:<>/sites/samples/blob_link_builder
http://docs.oracle.com/middleware/1221/wcs/develop/GUID-C8899CBC-2EC1-4A25-A887-F8B9A868084D.htm#WBCSD8200
Edit : since then I'm using a different solution, I use vanity URL for blob. Instead of doing a template I just take the AssetType, create a vanity URL that will apply for the blob attribute of my asset. This is far more easy than doing any template to display an image or something like that.

Related

How to reference a gist stylesheet in another gist?

I created a gist that has a html page and a css file. How would I reference the css file in the html page?
I tried a few ways but none of them seems working. The html page is at: https://gist.github.com/yuipcheng/943286be35fd690f499d59534281a6c5
Viewing page: https://gistpreview.github.io/?943286be35fd690f499d59534281a6c5
gistpreview.github.io loads the html with Javascript by using the Github Gist API. From the source code it just writes the html content. So, it doesn't deal with relative links that may link to other css files.
You would need to :
fork the gistpreview project
after the html rendering (document.write), iterate over the link tags and check if they are present in the files field of the API result
load the css content dynamically if matching
I've tested this method above using this fork.
Example for you gist: https://bertrandmartel.github.io/gistpreview.github.io/?943286be35fd690f499d59534281a6c5
Code before :
var content = info.files[fileName].content;
document.write(content);
Code after :
var content = info.files[fileName].content;
document.write(content);
//load links
var links = document.querySelectorAll("link");
for (let [key, value] of Object.entries(info.files)) {
for (var i = 0; i < links.length; i++) {
var href = links[i].getAttribute("href").replace(/^\/|\/$/g, '');
if (value.filename === href && value.type === "text/css") {
console.log("load file " + value.filename);
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = value.content;
document.getElementsByTagName('head')[0].appendChild(style);
}
}
}

Embed google-plus in GWT

I am trying to embed Google-Plus into my GWT Application. I would like it to be embedded into a HorizontalPanel. I did read +1button developers google. I didn't find any post about this particular problem in stackoverflow. My problem might be that I don't understand how to include the js into a GUI component. I would appreciate an Example of how to add the Google+ code into a Panel.
Here is how to do it:
Documentation:
<!-- Place this tag in your head or just before your close body tag -->
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
<!-- Place this tag where you want the +1 button to render -->
<g:plusone></g:plusone>
in GWT:
private void drawPlusOne() {
String s = "<g:plusone href=\"http://urltoplusone.com\"></g:plusone>";
HTML h = new HTML(s);
somePanel.add(h);
// You can insert a script tag this way or via your .gwt.xml
Document doc = Document.get();
ScriptElement script = doc.createScriptElement();
script.setSrc("https://apis.google.com/js/plusone.js");
script.setType("text/javascript");
script.setLang("javascript");
doc.getBody().appendChild(script);
}
I've personally never embedded the +1 button in GWT, but the linked article seems pretty self explanatory.
In the section "A Simple Button", it indicates that the simplest way of implementing GooglePlus integration is to add this:
<script src="https://apis.google.com/js/plusone.js" />
<g:plusone></g:plusone>
First, the <script> tag should be included in your .gwt.xml file.
Then I'd implement the <g:plusone></g:plusone> like this:
public class GPlusOne extends SimplePanel {
public GPlusOne () {
super((Element)Document.get().createElement("g:plusone").cast());
}
}
(Note that this code is untested, but it's based on the simple concept that a SimplePanel can be extended to compile as any HTML element.)
Then you'd use the new GPlusOne element wherever you'd want the button to show.
I found a better way to do it:
Follow this example to have the button work on invocation on a normal html page (you can try one here http://jsfiddle.net/JQAdc/)
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<script src="https://apis.google.com/js/plusone.js">
{"parsetags": "explicit"}
</script>
<script type="text/javascript">
function gPlusBtn(id, params) {
/* window.alert("searching for "+ id +" with params: "+ params) */
paramsObj = eval( '('+params+')' );
gapi.plusone.render(id, paramsObj );
}
// params is here just for a reference to simulate what will come from gwt
params = '{href:"http://1vu.fr", size:"tall"}';
</script>
</head>
<body>
taken from http://jsfiddle.net/JQAdc/
<div id="gplus" />
<button onclick="gPlusBtn('gplus', params)">show!</button>
</body>
</html>
Then you can call a native method to trigger the button display on Activity start (if you're using MVP).
protected native void plusOneButton(String id, String params) /*-{
$wnd.gPlusBtn(id, params);
}-*/;
You can have multiple buttons with different urls, that's why id is left as a parameter.
NOTE: for me the raw HTML works on localhost, but the GWT version. I have to deploy to the server to be able to see the results

Image, link and title for Facebook like button at the product list.

How can I display the right image, title and link for a Facebook Like button in a list of products?
I do implement sucessfully the like button but it is when you navigate to the product details, you see only one product.
I ask how can i do it in the list of products, for now the image displayed on my facebook page is a generic image from the site and not the specific image of the product, the link is right.
Must the tag <meta property="og:image" content="some value"/> only be inside the head tag? I cannot use it inside the body tag?
The meta tags for the news story don't need to be on the page that is displaying the Like button. The news story will be generated from the meta tags on the page listed in the URL parameter of the Like button.
Here is an example. -
This Repeater will dynamically generate a list of products from a database with customized Like buttons:
<asp:Repeater ID="_RPT_Product" runat="server">
<HeaderTemplate><h3>Products</h3><ul class="bulleted-list"></HeaderTemplate>
<ItemTemplate><li><%# Utilities.ScrubText(((Product)Container.DataItem).ProductName) %>
</li>
<div style="padding-top:10px;">
<iframe
src="https://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.yourdomainname.com/Product.aspx%3FID%3D<%#((Product)Container.DataItem).ProductID %>%26x%3D1&send=false&layout=button_count&width=88&show_faces=false&action=like&colorscheme=light&font&height=23"
scrolling="no" frameborder="0"
style="border:none; overflow:hidden; width:88px; height:23px;"
allowTransparency="true">
</iframe></div><br />
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
This would be the code-behind on a separate Product page that dynamically renders meta tags from a product database:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// Get the product meta content from the ID URL parameter.
string productName = "";
string productImageURL = "";
string productDescription = "";
int productID = 0;
if (Request.QueryString["ID"] != null)
{
productID = Convert.ToInt32(Request.QueryString["ID"]);
}
if (Request.QueryString["ID"] != null)
{
using (ProductDatabaseDataContext db = new ProductDatabaseDataContext(Config.ConnectionStrings.ProductDatabase))
{
Product select = new Product();
select = db.Products.FirstOrDefault(p =>
p.ProductID == Convert.ToInt32(Request.QueryString["ID"]));
productName = select.ProductName;
productImageURL = select.ProductImageURL;
productDescription = select.ProductDescription;
}
}
// Dynamically generate Open Graph Meta Tags for each Product:
HtmlMeta _metaTitle = new HtmlMeta();
_metaTitle.Name = "og:title";
_metaTitle.Content = "Product: " + productName;
this.Header.Controls.Add(_metaTitle);
HtmlMeta _metaURL = new HtmlMeta();
_metaURL.Name = "og:url";
_metaURL.Content = "http://www.yourdomainname.com/Product.aspx?ID=" + Convert.ToString(productID);
this.Header.Controls.Add(_metaURL);
HtmlMeta _metaImage = new HtmlMeta();
_metaImage.Name = "og:image";
_metaImage.Content = Convert.ToString(productImageURL);
this.Header.Controls.Add(_metaImage);
HtmlMeta _metaDescription = new HtmlMeta();
_metaDescription.Name = "og:description";
_metaDescription.Content = Convert.ToString(productDescription);
this.Header.Controls.Add(_metaDescription);
}
}
Note that every Like button must have a unique URL parameter, because only one set of meta content attributes can be tied to a single URL. This can be accomplished by having a unique ID parameter on your separate Product.aspx page. The "og:url" meta tag for each of your products can be the same if you just want all of the product news stories to link back to one master list page.
The Like button likes a specific URL and if it's a product the user is liking, that link really should bring users back to a description of that product and not to a completely different set of content.
What you display on that propduct page itself isn't really important (it could be the full product list if you really wanted) provided that that URL returns the same meta tags to the Facebook crawler each time
What you're trying to do could be achieved by setting up a script which serves the meta tags for each product based on URL parameters (making sure to keep the og:url tags pointing to the correct URL to generate the same tags again.
Serve those tags to the Facebook crawler and redirect other browsers wherever you want.

Writing script src dynamically via wicket

I want my page to load javascript dynamically to my body:
<script type= "text/javascript" src="this path should be decided from wicket dynamically"/>
I am using wicket version 1.4 therefore JavaScriptResourceReference does not exist in my version (for my inspection it wasn't ' )
how can I solve this ?
thanks in advance :).
I specify my comment into an answer.
You can use this code snippet:
WebMarkupContainer scriptContainer = new WebMarkupContainer("scriptContainer ");
scriptContainer .add(new AttributeAppender("type", Model.of("text/javascript")));
scriptContainer .add(
new AttributeAppender("src", urlFor(
new JavaScriptResourceReference(
YourClass.class, "JavaScriptFile.js"), null).toString()));
add(scriptContainer );
and the corresponding html:
<script wicket:id="scriptContainer "></script>
Just change the string JavaScriptFile.js to load any other Javascript file.
JavascriptPackageResource.getHeaderContributor() does exactly what you need.
You need nothing in your markup, just add the HeaderContributor it returns to your page.
Update: For Wicket 1.5 see the migration guide, but it goes like this:
public class MyPage extends WebPage {
public MyPage() {
}
public void renderHead(IHeaderResponse response) {
response.renderJavaScriptReference(new PackageResourceReference(YuiLib.class,
"yahoo-dom-event/yahoo-dom-event.js"));
response.renderCSSReference(new PackageResourceReference(AbstractCalendar.class,
"assets/skins/sam/calendar.css"));
}
}
If you want to put your <script> element in the body, you can simply declare it as a WebMarkupContainer and add an AttributeModifier to set the src attribute. Although in that case wicket won't generate the relative URLs for you, you have to do it yourself.
I'm not sure I understood completely.
If you are trying to create and append a script to the body after the page is loaded you should do it this way:
<script type="text/javascript">
function load_js() {
var element = document.createElement("script");
element.src = "scripts/YOUR_SCRIPT_SRC.js"; // <---- HERE <-----
document.body.appendChild(element);
}
// Wait for the page to be loaded
if(window.addEventListener)
window.addEventListener("load",load_js,false);
else if(window.attachEvent)
window.attachEvent("onload",load_js);
else
window.onload = load_js;
</script>
What I did here is create a new script element, and then apply to it its source.
That way you can control dynamicaly the src. After that I append it to the body.
The last part is there so the new element is applied only after the page is loaded.

MVC 2 Templates - Is it possible to redirect the current editor template to its display template based on metadata?

For a project I'm working I've been asked to redirect an editor template to its display template based on metadata that is provided with the model.
Now I was looking at a way to do it before it hits the editor template but that seems to cause more issues than it is worth, at least with how the system has been architected.
The simplest example is the string editor, its a simple textbox but if IsReadOnly is set we want it to only show up as text, not a disabled textbox.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%
if (this.ViewData.ModelMetadata.IsReadOnly)
{
Response.Write(Html.DisplayForModel());
}
else if (this.ViewData.ModelMetadata.ShowForEdit)
{
<%= Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { #class = "text-box single-line" }) %>
<% } %>
So far the only real solution I can find is to copy the display template into the editor template. Does anyone have any ideas how I can do something that will work without replicating more code?
Why not do this outside of the editor template itself? Define an extension method that checks if the property is read only then either shows the edit or display template. You'll need to copy the PropertyHelper class from this answer.
public MvcHtmlString DisplayOrEditFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> selector)
{
var property = PropertyHelper<TModel>.GetProperty(selector);
if(property.CanWrite)
{
return helper.EditorFor(selector);
}
return helper.DisplayFor(selector);
}
Then in your view just do
<%: Html.DisplayOrEditFor(x => x.Name) %>
Only drawback is this won't work with Html.EditorForModel().