Composite C1 - Using MVC RenderSections or the like - c1-cms

In Composite C1 I'm using Razor syntax to create my master layout. For faster loadtimes it's recommended to put your scripts just before the end body tag instead of inside the head tag. That's why I put jQuery and other scripts just before the end body tag.
When I use a Razor function with JavaScript that refers to jQuery I get an error because jQuery hasn't been loaded yet. The HTML from the Razor function is output before the jQuery script is loaded:
Uncaught ReferenceError: $ is not defined
In MVC I can use RenderSection in the master layout to accomplish this (rendering the JavaScript below my master layout scripts
#RenderSection("FooterScripts", false)
Then in my views I can define a section like this:
#section FooterScripts {
<script type="text/javaScript">
$(function () {
...
});
</script>
}
Which will render the HTML in the correct place in the final HTML. Is this possible to do in Composite C1? I couldn't get RenderSection to work even though Intellisence tells me it's available.

There's no built in way to insert html markup from a C1 function to a specific place in a layout.
Possible ways to implement your own logic would be:
Collect the scripts to be insterted in f.e. Context.Items collection, and insert them in the end.
Implement some post processing logic that would move the script tags to the bottom of the page after it is rendered.
First way is easier to implement, here's a short working example:
C1 Function code:
#inherits RazorFunction
#using Composite.Examples
#functions {
}
#{
LayoutHelper.AddDelayedScript(Script());
}
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
Inserting a script at the bottom of a page
</body>
</html>
#helper Script() {
<script type="text/javascript">
alert("I'm inserted!");
</script>
}
Layout code:
....
#LayoutHelper.RenderDelayedScripts()
</body>
</html>
Class LayoutHelper, defined in App_Code:
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace Composite.Examples
{
public static class LayoutHelper
{
private const string HttpItems_Key = "delayedscripts";
public static void AddDelayedScript(IHtmlString script)
{
var context = HttpContext.Current;
lock (context.Items.SyncRoot)
{
if (!context.Items.Contains(HttpItems_Key))
{
context.Items.Add(HttpItems_Key, new List<IHtmlString>());
}
(context.Items[HttpItems_Key] as List<IHtmlString>).Add(script);
}
}
public static IHtmlString RenderDelayedScripts()
{
var context = HttpContext.Current;
var sb = new StringBuilder();
if (context.Items.Contains(HttpItems_Key))
{
foreach (var delayedscript in context.Items[HttpItems_Key] as IEnumerable<IHtmlString>)
{
sb.Append(delayedscript.ToHtmlString());
}
}
return new HtmlString(sb.ToString());
}
}
}

Related

React ES6 class method does not render into html table but outside it. Why?

I want to understand ES6 and are using HTML table to render external React elements. Having trouble rendering this ES6 class into a html table.
I've tried rendering ES6 object from inside the class by returning a string to a HTML table which didn't render so now I render it externally to the class which renders to the bottom outside the table. I am using external CSS for the table and none of the other rendered elements are affected and are rendering to thier cells.
React.js
//PROBLEM: To create an igor skate from an inline skate model.
//START
//CREATE Class Roller_Blades.
//CONSTRTUCT property Name "Inline Skate"
//RETURN SkateType "I am a " Name " designed for mass production."
//END CLASS
class InlineSkate {
constructor(name) {
this.brand = name;
}
present() {
return "I am a " + this.brand + " designed for mass production."
}
}
//This string outside the class will output 'K2 Skate' back into
// InlineSkate.CreateRollerBlade().
var skate = new InlineSkate('K2 Skate');
document.write(skate.present());
ReactDOM.render(React.createElement(InlineSkate, null), document.getElementById('esSixClassExample'));
HTML
<body>
<!--Output-->
<table ID="DoubleBorderedTable">
<tbody>
<tr>
<th>ES6 Class Example</th>
</tr>
<tr>
<td><div id="hello-example"></div></td>
<td><div id="clock-example"></div></td>
<td><div id="es6ClassExample"></div></td>
</tr>
</tbody>
</table>
<!-- Load React. -->
<!-- Note: when deploying, replace "development.js" with
production.min.js". -->
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<!-- Load our React components.-->
<script src="scripts/simple_component.js"></script>
<script src="scripts/Clock.js"></script>
<script src="scripts/ESSixClassExample.js"></script>
</body>
The class function "present" that returns a string ends up rendering outside and below the table and not in the desired last cell of the last row of the table.
ReactDOM.render(React.createElement(InlineSkate, null), document.getElementById('esSixClassExample'))
This is doing nothing. I'd be willing to bet that if you opened your console you'd see an error that says something like, "Cannot call a class as a function".
What's printing the string outside the table are these two lines,
var skate = new InlineSkate('K2 Skate');
document.write(skate.present());
As it is you aren't really using React at all. The first argument of ReactDOM.render() should be either a function component, a class component, or a string designating the type of element to be created.
In order to get the output you want without changing what you're doing so much, you'd need to do something like this,
var skate = new InlineSkate("K2 Skate");
ReactDOM.render(
React.createElement("span", { children: skate.present() }),
document.getElementById("esSixClassExample")
);
What that will do is create a span element, stick it inside your esSixClassExample div, and then run your present function to generate your text and assigning the text node as a child of the span.
This is pretty irregular though, and unless you're just doing this for learning purposes or as part of a class or something, you really ought to be using React components (because why even bother with React otherwise.)
Here is a class component example.
class InlineSkate extends React.Component {
render() {
return React.createElement(React.Fragment, null, "I am a ", this.props.brand, " designed for mass production.");
}
}
ReactDOM.render(React.createElement(InlineSkate, {
brand: "K2 Skate"
}), document.getElementById('classComponent'));
And here is a function component example.
function InlineSkate({ brand }) {
return React.createElement(React.Fragment, null, "I am a ", brand, " designed for mass production.");
}
ReactDOM.render(React.createElement(InlineSkate, {
brand: "K2 Skate"
}), document.getElementById('functionComponent'));

polymer 1.0 .. importing a catalog element with a custom element throws an error

Had created and used my custom polymer element which is a table. Now, I want to use the check box element from their catalog in my table.
However, I keep getting this error when I reference the check box html file in my index page:
DuplicateDefinitionError: a type with name 'dom-module' is already
registered
This is how I have created my custom element:
<!-- Imports polymer -->
<link rel="import" href="polymer/polymer.html">
<script src="underscore-min.js"></script>
<!-- Defines element markup -->
<dom-module id="custom-table" >
<template>
<style>
ul {list-style-type:none; display:block}
ul li {display:inline; float:left; padding:20px; width:1.5em; border-bottom:1px solid #eee}
</style>
<h2>{{title}}</h2>
<table id="dataTable">
<thead id="tableHead"></thead>
<tbody id="tableBody"></tbody>
</table>
</template>
</dom-module>
<!-- Registers custom element -->
<script>
Polymer({
is: 'custom-table',
// Fires when an instance of the element is created
created: function() {
},
// Fires when the local DOM has been fully prepared
ready: function() {
var context= this;
this.pageNo=0;
this.totalPages=0;
// set the default paging size:
if(this.page== null|| this.page==undefined)
this.page=10;
// delegate the change selection handler to the table body
this.$.tableBody.addEventListener("click",function(e){
if(e.target && e.target.nodeName == "INPUT") ;
{
context.changeSelection(e.target);
}
});
},
// Fires when the element was inserted into the document
attached: function() {},
// Fires when the element was removed from the document
detached: function() {},
// Fires when an attribute was added, removed, or updated
attributeChanged: function(name, type) {
alert("changed");
},
loadData: function(columns,data){
this.data = data;
// add the selected property to the values
for(var i=0;i<this.data.length; i++) { this.data[i].Selected = false;}
this.filteredData=this.data;
this.columns = columns;
//initialize the filteredData
this.filteredData=data;
// calculate the total number of pages
this.totalPages= Math.ceil(data.length/this.page);
this.drawTableHeader();
_.defer(this.applyFilters,this);
_.defer(this.drawTableBody,this);
},
drawTableHeader:function(){
var columns = this.columns;
// load the header
var headTr = document.createElement('tr');
//add a blank header for the check box;
var th=document.createElement('th');
headTr.appendChild(th);
for(var i = 0; i<columns.length ;i++)
{
var td=document.createElement('th');
// if the column is sortable then add the event listener for sorting it
if(columns[i].Sortable)
{
td.addEventListener("click",function(){ this.sortBy(columns[i].Title); });
}
td.innerText = columns[i].Title;
headTr.appendChild(td);
}
this.$.tableHead.appendChild(headTr);
},
drawTableBody: function(context){
// this is a defered function
var context = context;
// get the number of items according to the current page number
var pageItems= context.filteredData.slice((context.page*context.pageNo),((context.page*context.pageNo)+context.page));
console.log(pageItems);
// print the page items
for(var i=0; i < pageItems.length; i++)
{
var currItem = pageItems[i];
var tr= document.createElement("tr");
// add the check box first
var checkbox= document.createElement("input");
checkbox.type="checkbox";
checkbox.checked=pageItems[i].Selected;
var ItemId = currItem.Id;
checkbox.setAttribute("data-ItemId",ItemId-1);
var td=document.createElement('td');
td.appendChild(checkbox);
tr.appendChild(td);
// for every column specified add a column to it
for(var j = 0; j< context.columns.length; j++)
{
var td=document.createElement("td");
td.innerText= pageItems[i][context.columns[j].Title];
tr.appendChild(td);
}
//append the row to the table;
context.$.tableBody.appendChild(tr);
} // end for i
},
applyFilters:function(context){
if(context.filter)
{
alert("filterApplied");
}
},
changeSelection:function(checkbox){
var ItemId = checkbox.getAttribute("data-ItemId");
this.data[ItemId].Selected= checkbox.checked;
console.log(this.data[ItemId]);
},
properties:{
title :String,
columns:Array,
data:Array,
page:Number,
filters:Object,
Selectable:Boolean
}
});
</script>
and here is what my index page looks like:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title><my-repo></title>
<!-- Imports polyfill -->
<script src="webcomponents-lite.min.js"></script>
<!-- Imports custom element -->
<link rel="import" href="my-element.html">
<link rel="import" href="bower_components/paper-checkbox/paper-checkbox.html">
</head>
<body unresolved>
<!-- Runs custom element -->
<custom-table title="This is data table"></custom-table>
<script>
document.addEventListener("WebComponentsReady",function(){
var data = [{'Id':1,'firstName':'aman',age:25},{'Id':2,'firstName':'gupta',age:25}];
var cols = [{Title:'firstName',Sortable:true},{Title:'age',Sortable:false}];
var a = document.querySelector('my-element');
a.loadData(cols,data);
});
</script>
</body>
</html>
I've just started out with polymer and I'm not quite sure what's going on here..
Thank you in advance :)
I got what the problem is..
My custom element was referencing a different Polymer.html file.
Silly me :D
I'm using Polymer Starter Kit Yeoman generator on Windows and I had the same problem:
Error: DuplicateDefinitionError: a type with name 'dom-module' is already registered
This error is triggered in Firefox console. Chrome works fine.
The components created with the generator (example: yo polymer:el my-element) have this polymer.html import:
<link rel="import" href="..\..\bower_components/polymer/polymer.html">
The base path is described with "backslash".
In some custom polymer elements I created by myself, I imported polymer.html with:
<link rel="import" href="../../bower_components/polymer/polymer.html">
And I think this lead to a duplication of some kind. To solve the problem, I just changed all automatically created imports, using only forward slashes /.
Hope this helps someone.

follow up on how to stop SalesForce style overwrite

following up on
https://stackoverflow.com/questions/27975991/neptune-theme-buttons-unreadable- with-light-grey-backgrounds-on-visualforce-page
The sf css extended.css is loading after neptune.css and therefore overriding neptune for body button, body .x-btn etc.
I found this:
https://salesforce.stackexchange.com/questions/24575/how-to-ignore-salesforce-css-on-vf-page-with-header
in which the first answer with the jQuery link seems to be the most elegant. However I need help on this -
$("head").append("link rel='stylesheet' href='/css/masterBlaster.css' type='text/css' media='screen'"); and
$("head link[rel='stylesheet']").last().after("link rel='stylesheet' href='/css/masterBlaster.css' type='text/css' media='screen'");
are standard html css, not the sf way of
apex:stylesheet value="{!URLFOR($Resource.ExtJS42, '/ExtJS42/resources/ext-theme-neptune-all.css')}"
How is Bob Buzzard implementing this in apex-speak? tia.
removed the "<>" out of above code to get it to display
The code snippets that you have posted, e.g.
$("head").append("link rel='stylesheet' href='/css/masterBlaster.css' type='text/css' media='screen'");
are JavaScript that relies on the JQuery library being present, so you'd actually need something like the following:
At the top of the file include jQuery - this is from a CDN, but you might want it as a static resource:
<apex:includescript value="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js" />
Then in the body
<script>
$(document).ready(function(){
$("head").append("link rel='stylesheet' href='/css/masterBlaster.css' type='text/css' media='screen'");
});
</script>
putting this inside the ready handler means it will run as soon as the page is loaded.
<script type="text/javascript" >
j$ = jQuery.noConflict();
j$(document).ready(function() {
var stylesheet = document.styleSheets[(document.styleSheets.length - 1)];
for( var i in document.styleSheets ){
if( document.styleSheets[i].href && document.styleSheets[i].href.indexOf("extended.css")>0 ) {
stylesheet = document.styleSheets[i];
stylesheet.id = "cmnSheet"; // id would allow dynamic mods?
stylesheet.disabled = true;
break;
}
};
});
extjs css is loaded in apex page tag with
'<'apex:stylesheet value="{!URLFOR($Resource.ExtJS42, '/ExtJS42/resources/ext-theme-neptune-all.css')}" /'>'
(typing jQuery stuff from memory and notes so will correct later if needed but concept is there)

How to notify an user when he tries to close a tab or close the browser

First of all, I always say the same: sorry about my english is very weak. I hope you can understand me well.
I need to notify an user when he tries to close a tab or close the browser.
Is there any way to fire an event to avoid the browser will be closed?
The application is made in silverlight.
Thanks in advance.
Take a look at the following example, there is also a sample application:
http://www.blog.jonnycornwell.com/2011/01/23/using-silverlight-and-javascript-to-prevent-leaving-a-webpage/
It's about using Silverlight and JavaScript to prevent leaving a webpage.
The javascript:
<script language="javascript" type="text/javascript">
window.onbeforeunload = askConfirm;
function askConfirm() {
var control = document.getElementById("silverlightControl");
var preventLeave = control.Content.Page.PreventLeave();
if (!preventLeave) {
return;
}
var message = control.Content.Page.LeaveRequested();
return message;
}
</script>
The silverlight code:
public MainPage()
{
InitializeComponent();
HtmlPage.RegisterScriptableObject("Page", this);
}
[ScriptableMember]
public string LeaveRequested()
{
return "You have unsaved changes to your current document?";
}
[ScriptableMember]
public bool PreventLeave()
{
return (bool)PreventLeaveCheckBox.IsChecked;
}
This can be done easily with javascript. For example:
<html>
<head>
<script type="text/javascript">
<!--
function closeIt(url,name)
{
return "Hi there! I'm a message!";
}
window.onbeforeunload = closeIt;
// -->
</script>
</head>
<body>
<p>I'm a webpage!</p>
</body>
</html>

Telerik MVC Grid - ClientTemplate()

I have a DateTime that is rendering in the grid via ClientTemplate() like this:
/Date(1294030800000)/
I know it is a valid date.
Has anyone seen this or can provide a clue as to what I am doing wrong?
Here is what I did (thanks to SLaks for pointing out that it was a JSON date) which reminded me that the Telerik grid serializes responses as JSON when in Ajax mode.
I created a helper function in my view:
<script type="text/javascript" language="javascript">
function ConvertToDateFromJSON(jsonDate) {
var regex = /-?\d+/;
var numbers = regex.exec(jsonDate);
var d = new Date(parseInt(numbers[0]));
return d;
}
</script>
And then the call to ClientTemplate goes like this:
columns.Bound(model => model.DateAdmitted)
.Template(o => o.DateAdmitted.ToString("d"))
.ClientTemplate(
"<#= $.telerik.formatString('{0:MM/dd/yyyy}', ConvertToDateFromJSON(DateAdmitted)) #>"
);

Resources