Monday, December 29, 2014

JSLink expand collapse documents

the expand/collapse is for each folder in the doc lib
note: you need to change the view to flat insead of folders (edite view -> style)

sample and example, with nano scroller, from my onedrive
https://onedrive.live.com/redir?resid=949DC4EDBFFD4738!254&authkey=!ACwGD9PzPMxqle0&ithint=file%2cjs

i just followed this fiddle http://jsfiddle.net/hungerpain/eK8X5/7/

and this is my extra css
.DocumentsZone { border-top: 1px solid #d4d4d4}
.docs-title-wrapper { margin: 20px 0 20px;}
.docs-title-wrapper h2.ms-webpart-titleText {display:inline-block; }
.docs-title-wrapper input{ border: none;width: 23px;height: 23px;min-width: 0;vertical-align: top;margin-top: 7px;background: url('/PublishingImages/+.png');}
.docs-wrapper ul {list-style:none;}
.docs-wrapper li {padding: 10px 0;}
.tree-header {cursor:pointer}
.tree-header > span {font-size: 17px;margin-left: 9px;line-height: 24px;vertical-align: bottom;}
.tree-content {display: none;}
.leaf-row1 > img {float:left;}
.leaf-row1 > span {font-size: 14px;color: #00aae7;vertical-align: super;margin-left: 26px;display: block;}
.leaf-row2 {margin-left:26px;}
.leaf-row2 span {margin-right:8px;}
.tree-allDocsLink {text-align: center;padding-right: 60px;margin: 30px 0;}
.tree-allDocsLink a { font-size: 12px;font-weight: bold;color: #00aae7;}

the result is:



Wednesday, December 17, 2014

JSLink Royal Slider Tutorial

if you havn't, take a look at the basic tutorial http://bresleveloper.blogspot.co.il/2014/12/js-link-tutorial-sharepoint-2013.html

the basic thing about royal slider is the wrapper
<div id="Slider" class="royalSlider rsDefault">

therefor the most logical solution is to use the Header-Item-Footer architecture.
and since I like to capsulate everything I do so here is my basic object

var jsLinkRoyalSlider = {};

jsLinkRoyalSlider.HeaderOverrideFun = function (ctx) {
    return '<div id="Slider" class="royalSlider rsDefault">';
};

jsLinkRoyalSlider.ItemOverrideFun = function (ctx) {
};

jsLinkRoyalSlider.FooterOverrideFun = function (ctx) {
    return '</div>';
};

jsLinkRoyalSlider.Constuctor = function () {
    var overrideCtx = {};
    overrideCtx.Templates = {};
    overrideCtx.Templates.Header = jsLinkRoyalSlider.HeaderOverrideFun;
    overrideCtx.Templates.Item = jsLinkRoyalSlider.ItemOverrideFun;
    overrideCtx.Templates.Footer = jsLinkRoyalSlider.FooterOverrideFun;
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
};


(function () {
    jsLinkRoyalSlider.Constuctor();
})();
 


now for the item, each should look like this

<div class="rsContent">
    <a class="rsImg" data-rsBigImg="pictureURL" href="pictureURL"></a>
    <div class="infoBlock blockBottomline">
        <!-- content -->
    </div>
</div>

so lets fill the ItemOverrideFun function
   
var pictureURL = ctx.CurrentItem.FileRef;
var title = ctx.CurrentItem.Title;
var desc = ctx.CurrentItem.Description;
return '<div class="rsContent">' +
            '<a class="rsImg" data-rsBigImg=" ' + pictureURL + ' " href="' + pictureURL + '" ></a>' +
            '<div class="infoBlock blockBottomline">' +
                 '<div class="TitelBlock">' + title + ' </div>' +
            '</div>' +
       '</div>';

function all that's left is to initiate the royal slider, I would use jQuery but there still isn't jQuery yet here, do I used the native "ready" function (not supported in IE8, there either load JQ, or use onload) in my anonymous constructor function

document.addEventListener("DOMContentLoaded", function (event) {
  $(".royalSlider").royalSlider({
    arrowsNav: false,
    controlNavigation: 'bullets',
    imageScaleMode: 'none',
    imageAlignCenter: false,
    loop: true,
    transitionType: 'fade',
           
    autoPlay: {
 
     stopAtAction: false,
      enabled: true,
      delay: 5000
    }
  });
});
 


now, for some reason, and I blame the JSLink here, there was a script element between my item, so I used the OnPostRender function to remove it

overrideCtx.OnPostRender = jsLinkRoyalSlider.PostRenderHandler;

jsLinkRoyalSlider.PostRenderHandler = function (ctx) {
   $("script", "#Slider").remove();
};

and here is my final script from my onedrive
https://onedrive.live.com/redir?resid=949DC4EDBFFD4738!253&authkey=!AFsjHYj0nj8fhfc&ithint=file%2cjs

JS Link Tutorial, Sharepoint 2013

there are many suppose to be tutorial about JSLink, but none start form the beginning
some history http://bresleveloper.blogspot.co.il/p/evolution.html

basically JSLink is the cliend side way of data-binding and rendering you sharepoint things to ... well it can be sharepoint lists and libraries and it can be your pages.

it works like this, the moment you put a url to your js file the item / field / webpart sends all of its data to the client and run your js

so what do we have? well best putted is this image from this blog:
http://www.codeproject.com/Articles/620110/SharePoint-Client-Side-Rendering-List-Views

this means that each part you see here is actually a JS function that accepts the context with all the data and returns some HTML

(function () {
    var overrideCtx = {};
    overrideCtx.Templates = {};
    overrideCtx.Templates.Header = HeaderOverrideFun;
    overrideCtx.Templates.Item = ItemOverrideFun;
    overrideCtx.Templates.Footer = FooterOverrideFun;
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
})();

 
function HeaderOverrideFun(ctx) {
    return "<div> <h1> BIG TITLE </h1> <ul>"
}
function ItemOverrideFun(ctx) {
    return "<li>" + ctx.CurrentItem.Title + "</li>";
}
function FooterOverrideFun(ctx) {
    return "</ul> <h6> small footer </h6> </div>"
}

go ahead and try it, just add any web part from your apps gallery (which is your lists)

NOTE that the (function () { ... } )(); is just a way to register an anonymous function and run it immediately, you would achieve the same with strait writing the cold like this

var overrideCtx = {};
overrideCtx.Templates = {};
overrideCtx.Templates.Header = HeaderOverrideFun;
overrideCtx.Templates.Item = ItemOverrideFun;
overrideCtx.Templates.Footer = FooterOverrideFun;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);

 
writing or wrapping it with a named function and calling it:
 
function go() {
    var overrideCtx = {};
    //...
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideCtx);
};
go();
 


with most example you will see the anon ctor for convenient and encapsulation.

so we've seen Header, Item, Footer, where is the rest?

well if you use Body and Groups you will not get to use the Items function, instead you will have to write your own loop

for (var i = 0; i < ctx.ListData.Row.length; i++) {
    var listItem = ctx.ListData.Row[i];
    var ID = parseInt(listItem['ID']);
    var row = document.getElementById(GenerateIIDForListItem(ctx, listItem));
    if (row) {
        if ( (ID % 2) === 0 ) {
            row.style.backgroundColor = 'blue';
        }

    }
}
 


There is an hierarchy:
if you use View than you have nothing but it.
with Body you have Groups and Header and Footer, but not item.
if you dismiss the above you get to use item.

about customizing fields see more here
http://www.codeproject.com/Articles/620110/SharePoint-Client-Side-Rendering-List-Views


AND IF I NEED CALLBACKS?
haha, yes you have it. the template has Pre and Post render callbacks,

overrideCtx.OnPreRender = PreRenderHandler;
overrideCtx.OnPostRender = PostRenderHandler;
 


you can do anything you want there, PLUS you have the context with all its data!
BTW! the post render is AFTER the html is inserted to the DOM,
again thx to http://www.codeproject.com/Articles/620110/SharePoint-Client-Side-Rendering-List-Views


IS THAT IT?
well, yes and no.

for the webparts, as long as you have only 1 in your page you're ok. after that sharepoint doesn't know which you want to render, so you need to put identifiers, named ListTemplateType and BaseViewID

var overrideCtx = {};
overrideCtx.Templates = {};
overrideCtx.ListTemplateType = 109;
overrideCtx.BaseViewID = 1;
 


ListTemplateType is an enum, most values you have here, there rest you can find either on the net or just test it, and BaseViewID is usually 1, but sometimes it changes (or you want another one)
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.listtemplatetype

IS THAT IT?
almost. what if you need more columns than what you currently have? well the as you noticed there is this BaseViewID which is actually the view used for that list, so just add more columns to display in that view.
i tried to change the view in edit mode and it worked but not after saving into display mode, maybe if we would change the default view?...

next is a tutorial for Royal Slider!

Tuesday, December 16, 2014

how to add ScriptEditorWebPart to PageLayout

the simple secret is that the ID of the webpart MUST be a guid, example

<WebPartPages:ScriptEditorWebPart
    runat="server"
    Content="&lt;script&gt;alert(&#39;hi&#39;);&lt;/script&gt;"
    ID="g_9db1223f_1234_44df_ad5d_e6454520ddfa" >
</WebPartPages:ScriptEditorWebPart>

Sharepoint error while uploading file to masterpages gallery

the error:
Server error: The URL is invalid. It may refer to a nonexistent file or folder or refer to a valid file that is not in the current Web

כתובת ה- URL‏ '_catalogs/masterpage/tryAutoPromo2.aspx' אינה חוקית. ייתכן שהיא מפנה לקובץ או לתיקיה שאינם קיימים או מפנה לקובץ או לתיקיה חוקיים שאינם נמצאים באתר הנוכחי.

guess what? i just added 2 webparts with the same id

Thursday, December 11, 2014

ng-repeat working with JSON objects

today i had quite  a fight vs ng-repeat while trying to loop over some json objects
i'll just sum it cause in the end its quite easy. you can try it yourself, I prepared a little jsbon for it:
http://jsbin.com/roranijaba/1/edit?html,output

1 - simple array
this is just for the sake of the example, when your object in an array, ngRepeat looks like this
<div ng-init="friends = ['Jhonny','Jessy','Marky']">
  <ul>
    <li ng-repeat="friend in friends">
      {{friend}}.
    </li>
  </ul>
</div>



2 - array of json objects
this is where you can use the power of parameter with ngRepeat
<div ng-init="friends = [{name:'John', age:25, gender:'boy'},
       {name:'Jessie', age:30, gender:'girl'},
       {name:'Patrick', age:40, gender:'boy'}]">
  <ul>
    <li ng-repeat="friend in friends">
      {{friend.name}} who is {{friend.age}} years old.
    </li>
  </ul>
</div>


3 - json dictionay object
this is when your json obj acutally has  properties, while each represents an array of either simple values or json objects, here is an example of both
<div ng-init="friendsDictionary =
    { boys : [{name:'John', age:25, gender:'boy'},
              {name:'Peter', age:95, gender:'boy'}],
     girls : [{name:'Jessie', age:30, gender:'girl'},
              {name:'Samantha', age:60, gender:'girl'}]}">
  <ul ng-repeat="(gender, friends) in friendsDictionary">
    <li>{{gender}}</li>
    <li ng-repeat="friend in friends">
      {{friend.name}} who is {{friend.age}} years old.
    </li>
  </ul>
</div>


4 - json object of json objects - NO
you just cant do this, sorry. you must change the architecture to a json dictionay at least.

5 - putting ng-repeat in the same element of ng-controller - NO
you just cant do this, sorry. kind of understandable.

live example for all this :
http://jsbin.com/roranijaba/1/edit?html,output