Sage CRM Developers Course Implementing Screen Based Rules (2) Looking ahead to the classes DP01: Introduction to the Development Partner Program DP02: Entities and the Data Model (Part 1 of 2) DP03: Entities and the Data Model (Part 2 of 2) DP04: Implementing Screen Based Rules (Part 1 of 2) DP05: Implementing Screen Based Rules (Part 2 of 2) DP06: Screen and User Independent Business Rules DP07: Workflow (Part 1 of 2) DP08: Workflow (Part 2 of 2) DP09: Using the API Objects in ASP Pages (Part 1 of 2) DP10 : Using the API Objects in ASP Pages (Part 2 of 2) DP11: Using the Component Manager DP12: Programming for the Advanced Email Manager DP13: Using the Web Services API DP14: Using the Web Services API (Part 2 of 2) DP15: Coding the Web Self Service COM API (Part 1 of 2) DP16: Coding the Web Self Service COM API (Part 2 of 2) DP17: Using the .NET API (Part 1 of 2) DP18: Using the .NET API (Part 2 of 2) Agenda Sage CRM Client Side API Changes Introduced in Sage CRM v7.2 onChange Scripts Custom Content Using a Script Library Handling Mode Useful default client-side objects The Client Side API Changes Made in Sage CRM v7.2 Client Side Programming Changed in Sage CRM v7.2 Redesign of the interface All client side JavaScript has been separated into script libraries New client side API Powerful New Client Side API Very easy to use! – In Chrome, logon to CRM and Navigate to page – Press CTRL+SHIFT+J to open the JavaScript Console. Can mix with Plain Old JavaScript (POJ) Can extend with your own functions and script libraries Selecting Fields using the Client Side API crm.fields('comp_name') a single field can be selected by calling the fields method with it’s name as a parameter crm.fields('comp_name comp_type') multiple fields can be selected by sending a list separated by spaces crm.fields('!comp_name !comp_type') in this example all fields except the comp_name and comp_type field have been selected crm('comp_name') as a shortcut you can select fields by calling the crm function with the field name Simple Client Side API Methods value() – get value (code) text() – get text of field (translation) value(123) – set value cid() – get currency id caption() – get field caption caption('hello') –set field caption hide() – hides fields collapse() – collapses fields show() – shows fields highlight() – highlight field (defaults to yellow) highlight('pink') highlight(false) – remove highlight background('blue') bold() – embolden the text bold(false) – remove bold italic() underline() strike() - strikethrough strike(false) color('blue') – set font color fontSize(n) – where n is an integer number of pixels fontSize() – remove formatting title('text') – make a tooltip for a field title() – remove the title The Evolution of Scripting in Sage CRM. Coding Business Rules Made Easier Sage CRM v7.1 Sage CRM v7.1sp2 Sage CRM v7.1sp2 Sage CRM v7.2 • Plain Old JavaScript for Internet Explorer • POJ Cross Browser • jQuery • Sage CRM Client Side API Evolution of Script Sage CRM v7.1 Internet Explorer Only Sage CRM v7.1sp2 Cross Browser <SCRIPT> //This works only in Internet Explorer window.attachEvent("onload", hideButton) function hideButton(){var arrayTags = document.getElementsByTagName("A"); var re = new RegExp(CurrentUser.user_displayname,"i") if (!_Datalead_assigneduserid.innerText.match(re)) { for(i=0;i<arrayTags.length;i++) { if(arrayTags[i].href.search(/ValidateCompanyEntry/i )>-1) { arrayTags[i].style.visibility = hidden; } } } } </SCRIPT> <SCRIPT> if (window.addEventListener) { //firefox way of binding an eventwindow.addEventListener("load", hideButton, false) } else if (window.attachEvent) {//IE exclusive method for binding an eventwindow.attachEvent("onload", hideButton) } function hideButton() {var arrayTags = document.getElementsByTagName("A"); var re = new RegExp(CurrentUser.user_displayname,"i") if (!_Datalead_assigneduserid.innerText.match(re)) { for(i=0;i<arrayTags.length;i++) { if(arrayTags[i].href.search(/ValidateCompanyEntry/i)>-1) { arrayTags[i].style.visibility = hidden; } } } } </SCRIPT> Evolution of Script Sage CRM v7.1 (jQuery) Sage CRM v7.2 <script> $(function() { var strSelector = "#_Datalead_assigneduserid:contains('"+CurrentU ser.user_displayname+"')“ if ($(strSelector).length==0) { var jTags = $("A[href*='ValidateCompanyEntry']"); jTags.each(function() { $(this).hide(); }) } }); </script> <script> crm.ready(function(){ var x = crm("lead_assigneduserid").text(); if (x!=CurrentUser.user_displayname) { crm.hideButton("newopportunity.gif"); } }) </script> Field Level Scripting Using the onChange Event Simple onChange Scripts Takes advantage of browser event if (this.value.toUpperCase() == this.value) { window.alert(this.name + ' has been entered all uppercase') } Can use Plain Old JavaScript Sage CRM Client Side API Only Browser Objects are accessible Full access to DOM Full use of DHTML and object specific properties AJAX calls allow Server Side data to be fetched Sage CRM Client Side API can simplify field referencing Simple onChange Rules using Regular Expressions and Client Side API 1) The Field may only contain Letters and Numbers var strRuleMessage = 'Field may only contain Letters and Numbers'; re =/[^A-Za-z0-9]/; r = this.value.match(re); if(r) { //window.alert(strRuleMessage); //crm.infoMessage(strRuleMessage); crm.errorMessage(strRuleMessage); } 2) The field may only contain uppercase or lowercase letters. var strRuleMessage = 'The field may only contain uppercase or lowercase letters'; re =/[^A-Za-z]/; r = this.value.match(re); if(r) { //window.alert(strRuleMessage); //crm.infoMessage(strRuleMessage); crm.errorMessage(strRuleMessage); } Dependent Selection Example One field affecting the value of another Does not necessarily become a short Example comp_secterr in Company Entry script using Client Side API screen if (typeof(crm('pers_secterr').value()) != 'undefined') if (typeof(pers_secterr) != 'undefined') { { crm('pers_secterr').value(crm('comp_secterr' pers_secterr.value=comp_secterr.value; ).value()); } } Coding for an Intelligent Select if (this.value == ‘Training’){ document.forms[0].case_assigneduser idInput.onchange(); case_assigneduserid.value = '5'; } Note additional field: case_assigneduseridInput Client Side Example Needs to expand to Switch Statement. Difficult to Maintain Expanded Example for an Intelligent Select Sage CRM v7.1sp2 Sage CRM v7.2 document.forms[0].case_assigneduseridInput.onchange(); document.forms[0].case_assigneduseridInput.onchange(); switch (this.value) { var fcase_assigneduserid = crm('case_assigneduserid'); case 'Database' : switch (this.value) { case 'Database' : case_assigneduserid.value = '15'; fcase_assigneduserid.value('15'); break; break; case 'Documentation' : case 'Documentation' : case_assigneduserid.value = '14'; fcase_assigneduserid.value('14'); break; break; case 'Install' : case 'Install' : fcase_assigneduserid.value('15'); case_assigneduserid.value = '15'; break; break; case 'Software' : case 'Software' : fcase_assigneduserid.value('14'); case_assigneduserid.value = '14'; break; break; case 'Training' : case 'Training' : fcase_assigneduserid.value('15'); break; case_assigneduserid.value = '15'; default : break; default : case_assigneduserid.value = '5'; } fcase_assigneduserid.value('5'); } Custom Content Adding HTML and Script to Screens Custom Content Uses Use of Custom Content to add <span class=notification> HTML tags <span></span> <style></style> <input type=hidden name=screenmode value=save> Hello Mum</span> – Explore how access extra hidden field values in Create and Validate script text-decoration:overline; <iframe> – May run into refresh problems with <IFRAME>, consider including additional information by use of Create Script and Caption Code. <script> <object> <style> .ButtonItem{ color:red; font-family: Verdana; font-size: 16px; cursor:crosshair;} </style> <input type=button value='hello' onclick=window.alert('message')> <IFRAME scrolling='no' FRAMEBORDER='no' NAME="content_frame" width="100" height="30" SRC="http:\\server\crm\frameexample.htm"> </IFRAME> Custom Content and Coding Custom Content can contain <script> tags Useful for defining functions used in OnChange scripts or controlling on screen elements Simple JavaScript or Client Side API can be used <script> function checkCase(x) { var keyLockx = x.substr(0,1).toLowerCase()+x.substr(1).toUpperCase() if (x == x.toUpperCase()||x == x.toLowerCase()||x==keyLockx) { x = x.substr(0,1).toUpperCase()+x.substr(1).toLowerCase(); return x; } else { return x; } } </script> Easy to bind Scripts to Screen Loading in Custom Content Sage CRM v7.1 Sage CRM v7.2 <SCRIPT> if (window.addEventListener) { window.addEventListener("load", setStatusColor, false) } else if (window.attachEvent) { window.attachEvent("onload", setStatusColor) } function setStatusColor() { if (_Datacomp_status.innerHTML == "Closed&nbsp;") { _Datacomp_status.style.color= "Red"; } } </SCRIPT> <SCRIPT> crm.ready(function(){ if (crm("comp_status").value()== "Closed") { crm("comp_status").highlight(“red"); } } ) </SCRIPT> Script Libraries Automatically Reusing Code Between Screens Reuse Between Screens in Sage CRM v7.1 sp2 <script> tag in Custom Content can take src parameter. <script src="/crm/custompages/rules.js"> </script> Create ‘rule’ file to reference in screen as needed. Client Side JavaScript Changes in Sage CRM v7.2 JavaScript files are no longer wrapped up in the eware.dll but are instead deployed to the client New folder in WWWRoot, called js, files added there (either in CRM or custom folders) will be deployed to the client. Creating a Custom Library Library Automatically included and available in all screens Defining object for Namespace Reference var CompanyRules = CompanyRules ||{}; var CompanyRules = CompanyRules ||{}; CompanyRules.addGoogleSearch = function(){ var fcomp_name = crm.fields("comp_name"); var strName = fcomp_name.text(); var strLink = "<A HREF=http://www.google.com/search?q="; if(fcomp_name.getMode()=="view") { fcomp_name.text(strLink+escape(strName)+" target=blank>"+strName+"</a>") }; } This line will either create a new object to act as the new namespace or return an existing one. CompanyRules.addStatusWarning = function(){ if (crm("comp_status").value ()== "Closed") { crm("comp_status").highlight("red"); } } Can now add own objects to namespace. Creating your own namespace objects helps code organisation and avoidance of clashes with existing objects and functions. Field & Data IDs for Client Script Standard Ids round all captions and data Essential information in Sage CRM v7.1sp2 Comp_name – _Datacomp_name – _Captcomp_name if (checked) { Address in Custom Content scripts / On Change Scripts etc MyField.style.visibility='visible'; – Target Style and other properties _CaptMyField.style.visibility='visible'; To make an entry (MyField) appear } if a checkbox is selected and else disappear when unselected the onchange for the check box would { be something like this: MyField.style.visibility='hidden'; _CaptMyField.style.visibility='hidden'; }; Using _capt & _data ids in Sage CRM v7.1sp2 To Control display color of comp_status data based on field value function setStatusColor() { <SCRIPT> switch (_Datacomp_status.innerHTML) if (window.addEventListener) { { case 'Active&nbsp;' : //firefox way of binding an event _Datacomp_status.style.color= 'Green'; window.addEventListener("load", setStatusColor, false) break; } case 'Archive&nbsp;' : else _Datacomp_status.style.color= 'Gray'; if (window.attachEvent) break; { case 'Closed&nbsp;' : //IE exclusive method for binding an event _Datacomp_status.style.color= 'Red'; window.attachEvent("onload", setStatusColor) break; } case 'Inactive&nbsp;' : _Datacomp_status.style.color= 'Yellow'; break; default : _Datacomp_status.style.color = 'Black'; } } </SCRIPT> Controlling fields in Sage CRM v7.2 <SCRIPT> crm.ready(function() { var fcomp_status = crm("comp_status").value(); switch (fcomp_status) { case 'Active' : crm("comp_status").highlight('Green'); break; case 'Archive' : crm("comp_status").highlight('Gray'); break; case 'Closed' : crm("comp_status").highlight('Red'); break; case 'Inactive' : crm("comp_status").highlight('Yellow'); break; default : crm("comp_status").highlight('Black'); } ///// }) </SCRIPT> Changing HTML Structure Sage CRM v7.1sp2 Sage CRM v7.2 <SCRIPT> if (window.addEventListener) { //firefox way of binding an event window.addEventListener("load", googleCompany, false) } else if (window.attachEvent) { //IE exclusive method for binding an event window.attachEvent("onload", googleCompany) } function googleCompany() { var strSpan=""; var strLink=""; if(!document.getElementById("comp_name")) { strSpan=_Datacomp_name.innerHTML; strLink="<A HREF=http://www.google.com/search?q="; strLink+=escape(strSpan)+" TARGET=blank>"+strSpan+"</A>"; _Datacomp_name.innerHTML = strLink; } } </SCRIPT> <SCRIPT> crm.ready(function() { // var fcomp_name = crm.fields("comp_name"); var strName = fcomp_name.text(); var strLink = "<A HREF=http://www.google.com/search?q="; if(fcomp_name.getMode()=="view") { fcomp_name.text(strLink+escape(strName)+" target=blank>"+strName+"</a>") }; }) </SCRIPT> Handling Mode Detecting when a screen is in Edit Mode, or in View Mode Detecting Mode in Custom Content Scripts CRM Screens can exist in different ‘Modes’ View Edit Save Can use following facts All Forms in CRM are called ‘EntryForm’ E.g. document.EntryForm.comp_name Use test for a field as Mode check –<INPUT> will only exists in Edit Mode Therefore to hide a field based upon the mode so that it is only available in View mode: Mode Checks are Easy in Sage CRM Client Side API Sage CRM v7.1sp2 Sage CRM v7.2 <SCRIPT> if (window.addEventListener) { //firefox way of binding an event window.addEventListener("load", modeCheck, false) } else if (window.attachEvent) { //IE exclusive method for binding an event window.attachEvent("onload", modeCheck) } <SCRIPT> //Detect Mode in Company Screen crm.ready(function() { var strMode = crm.fields("comp_name").getMode(); if (strMode=="edit") { crm.infoMessage(strMode); crm.fields("comp_status").collapse(); //crm.fields("comp_status").hide(); } else { crm.infoMessage(strMode); crm.fields("comp_status").show(); } }) </SCRIPT> function modeCheck() { var e=document.getElementById("comp_name"); if(e) { window.alert("Edit") _Datacomp_status.style.visibility = 'hidden'; _Captcomp_status.style.visibility = 'hidden'; } else { window.alert("View"); _Datacomp_status.style.visibility = 'visible'; _Captcomp_status.style.visibility = 'visible'; } } </SCRIPT> Client Side Objects Default Objects Available in Client Side Code onChange & Custom Content scripts in Upgraded Systems Installs of Sage CRM 7.1 need to have code checked for referenced to objects and functions that have changed in Sage CRM v7.2. Sage CRM v7.2 no longer uses Frames to draw its screens Objects/functions created in the eware_mid frame – CurrentUser and GetKeys() exist in the page in which the code runs. – These should be OK Objects created in other frames (in Sage CRM v7.1). – WritetoFrame() – Arrays (userslist, usersdislist, targetlistslist) – Andy code that references these objects will need to be changed and tested. Note: Although objects are client side and maybe used onChange scripts and custom content of screen & list blocks (including called by RunBlock) they are also used in ASP pages and .NET assemblies. Check Metadata for Business Rules executed in Browser select * from Custom_ScreenObjects where Cobj_CustomContent is not null select * from Custom_Screens where SeaP_OnChangeScript is not null; Clientside CurrentUser CurrentUser object automatically created by DLL driven pages. Has same Properties as Serverside CurrentUser object in Create Scripts. Can be used by any code in Custom Content <script> var strOut = "<ul>" var x; for (x in CurrentUser) { strOut+="<li>"+ x+"</li>"; } strOut += "</ul>" //document.write(strOut); crm.infoMessage(strOut); </script> Other useful Client side Objects GetKeys() This function is automatically available in system generated screens. It returns the context key string. E.g. – &Key0=1&Key1=28&Key2=30&Key4=1 Usage – <script> – crm.infoMessage(GetKeys()) – </script> Changes in Addressing TopContent WriteToFrame() and WriteToTopDiv Sage CRM v7.1sp2 Sage CRM v7.2 Function available in system screens that allows you to control contents of the TopContent frame. <SCRIPT> SageCRM.wsTop.WriteToTopDiv("Hello World"); <SCRIPT> Usage <SCRIPT> if (window.addEventListener) { window.addEventListener("load", RefreshTopContent, false) } else if (window.attachEvent) { window.attachEvent("onload", RefreshTopContent) } function RefreshTopContent() { parent.frames[3].WriteToFrame(5,"TOPBODY VLINK=NAVY LINK=NAVY",“Hello World"); } </SCRIPT> Q&A Looking ahead to the classes DP01: Introduction to the Development Partner Program DP02: Entities and the Data Model (Part 1 of 2) DP03: Entities and the Data Model (Part 2 of 2) DP04: Implementing Screen Based Rules (Part 1 of 2) DP05: Implementing Screen Based Rules (Part 2 of 2) DP06: Screen and User Independent Business Rules DP07: Workflow (Part 1 of 2) DP08: Workflow (Part 2 of 2) DP09: Using the API Objects in ASP Pages (Part 1 of 2) DP10 : Using the API Objects in ASP Pages (Part 2 of 2) DP11: Using the Component Manager DP12: Programming for the Advanced Email Manager DP13: Using the Web Services API DP14: Using the Web Services API (Part 2 of 2) DP15: Coding the Web Self Service COM API (Part 1 of 2) DP16: Coding the Web Self Service COM API (Part 2 of 2) DP17: Using the .NET API (Part 1 of 2) DP18: Using the .NET API (Part 2 of 2)