Tuesday, July 24, 2012

From the depths of SharePoint's sp.js Pt. 1

<Part 1>

Crack open your favorite browser tools and run:

ExecuteOrDelayUntilScriptLoaded( function() { console.dir( SP.Res ); }, 'sp.js');

The results will be:

LOG: {

 lcid : "1033",

 autocompleteAccessibleMenuName : "Autocomplete Menu",

 autocompleteLoading : "Loading...",

 autocompleteListNotFound : "List Not Found.",

 autocompleteListTooLarge : "List is too large to support Autocomplete.",

 autocompleteNoResults : "Item does not exist.",

 autocompleteTooManyResults : "Enter more of the name to see suggestions.",

 autocompleteList : "List:",

 autocompleteView : "View:",

 noObjectPathAssociatedWithObject : "The object is not associated with an object identity or the object identity is invalid.",

 propertyHasNotBeenInitialized : "The property or field has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.",

 collectionHasNotBeenInitialized : "The collection has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.",

 requestEmptyQueryName : "The property or query name is empty.",

 requestHasBeenExecuted : "Request has been executed.",

 requestAbortedOrTimedOut : "The request was aborted or timed out.",

 requestUnexpectedResponseWithStatus : "Unexpected response from server. The status code of response is '{0}'. The status text of response is '{1}'.",

 requestUnexpectedResponse : "Unexpected response from server.",

 invalidUsageOfExceptionHandlingScope : "Incorrect usage of exception handling scope.",

 unknownError : "Unknown Error",

 unknownResponseData : "Unexpected response data from server.",

 notSupportedQueryExpressionWithExpressionDetail : "The query expression '{0}' is not supported.",

 collectionModified : "The collection was modified. Enumeration operation may not execute.",

 cui_AddPerson : "Add Person or Group",

 calendarPrevMonth : "Previous Month",

 calendarNextMonth : "Next Month",

 calendarPrevWeek : "Previous Week",

 calendarNextWeek : "Next Week",

 calendarPrevDay : "Previous Day",

 calendarNextDay : "Next Day",

 oneMore : "1 more item",

 twoMore : "{0} more items",

 collapse : "collapse",

 calendarItemNew : "Add",

 calendarMenuLoading : "Loading items...",

 calendarRecurrenceException : "Exception to Recurring Event",

 calendarRecurrence : "Recurring Event",

 calendarNotifyLoading : "Loading calendar...",

 calendarNotifyUpdating : "Updating...",

 calendarErrorHeader : "Error",

 calendarClientDateOutOfSupportedRangeError : "Specified calendar is out of supported date range.",

 calendarDisabledWhileEditing : "This page may have been modified. You may need to reload this page to render the calendar view.",

 calendarDeleteConfirm : "Are you sure you want to delete this item?",

 calendarDateTimeSeparator : " - ",

 calendarViewEvent : "View Properties",

 calendarOpenItem : "Open",

 calendarResolveError : "No exact match was found for {0}.",

 invalidMerge : "The cells you are trying to merge do not have the same height or width. Change the size of the adjacent cells to match the selected cell before merging.",

 fontSizeUnitPt : "pt",

 fontSizeUnitPx : "px",

 fontSizeUnitEm : "em",

 fontSizeUnitCm : "cm",

 fontSizeUnitIn : "in",

 fontSizeUnitMm : "mm",

 fonts : "Fonts",

 themeFonts : "Theme Fonts",

 errorClipboard : "Your browser is not configured to allow access to your computer's clipboard. Use Control+X for Cut, Control+C for Copy, and Control+V for Paste.",

 clipboardNoAccess : "Your browser is not configured to allow access to your computer's clipboard. ",

 colorPickerStandardHeaderText : "Standard Colors",

 colorPickerThemeHeaderText : "Theme Colors",

 colorPickerMoreColorsText : "More Colors...",

 customBackgroundColorTitle : "Background Color",

 customColorTitle : "Color",

 editHtmlSourceTitle : "HTML Source",

 menuArrangeFloatTitle : "Float",

 menuArrangeInlineTitle : "Inline",

 selectMenuItemWithNumber : "{0} ({1})",

 selectMenuCENTER : "Centered text",

 selectMenuDIR : "Directory list",

 selectMenuFONT : "Font",

 selectMenuPLAINTEXT : "Plain text",

 selectMenuS : "Strikethrough",

 selectMenuSTRIKE : "Strikethrough",

 selectMenuU : "Underline",

 selectMenuXMP : "Plain text block",

 selectMenuRT : "Ruby text",

 selectMenuRUBY : "Ruby",

 selectMenuA : "Anchor",

 selectMenuABBR : "Abbreviation",

 selectMenuACRONYM : "Acronym",

 selectMenuADDRESS : "Address",

 selectMenuB : "Bold",

 selectMenuBDO : "Bi-directional text",

 selectMenuBIG : "Big text",

 selectMenuBLOCKQUOTE : "Quotation",

 selectMenuCAPTION : "Caption",

 selectMenuCITE : "Citation",

 selectMenuCODE : "Code",

 selectMenuDD : "Definition description",

 selectMenuDEL : "Deleted text",

 selectMenuDFN : "Definition",

 selectMenuDIV : "Text division",

 selectMenuDL : "Definition list",

 selectMenuDT : "Definition term",

 selectMenuEM : "Emphasized text",

 selectMenuFIELDSET : "Fieldset",

 selectMenuH1 : "Heading 1",

 selectMenuH2 : "Heading 2",

 selectMenuH3 : "Heading 3",

 selectMenuH4 : "Heading 4",

 selectMenuH5 : "Heading 5",

 selectMenuH6 : "Heading 6",

 selectMenuHR : "Horizontal rule",

 selectMenuI : "Italic",

 selectMenuIMG : "Image",

 selectMenuINS : "Inserted Text",

 selectMenuLABEL : "Label",

 selectMenuLEGEND : "Fieldset legend",

 selectMenuLI : "List Item",

 selectMenuMARQUEE : "Marquee",

 selectMenuMENU : "Menu list",

 selectMenuNOBR : "No line breaks",

 selectMenuOL : "Ordered list",

 selectMenuP : "Paragraph",

 selectMenuPRE : "Pre-formatted text",

 selectMenuQ : "Short quotation",

 selectMenuSAMP : "Sample",

 selectMenuSMALL : "Small text",

 selectMenuSPAN : "Span",

 selectMenuSTRONG : "Strong text",

 selectMenuSUB : "Subscript",

 selectMenuSUP : "Superscript",

 selectMenuTABLE : "Table",

 selectMenuTBODY : "Table body",

 selectMenuTD : "Table cell",

 selectMenuTFOOT : "Table foot",

 selectMenuTH : "Table header cell",

 selectMenuTHEAD : "Table head",

 selectMenuTR : "Table row",

 selectMenuTT : "Teletype text",

 selectMenuUL : "Unordered list",

 onPasteTooltip : "Paste Options",

 pasteTextLabel : "Keep Text Only",

 pasteStripLabel : "Remove Inline Styles",

 pasteHtmlLabel : "Keep Inline Styles",

 onCellTooltip : "Cell Menu",

 deleteRowLabel : "Delete Row",

 deleteColumnLabel : "Delete Column",

 splitCellLabel : "Split Cell",

 insertRowAboveLabel : "Insert Above",

 insertRowBelowLabel : "Insert Below",

 insertColumnLeftLabel : "Insert Left",

 insertColumnRightLabel : "Insert Right",

 pasteWaitScreenTitle : "Paste",

 pasteWaitScreenText : "Pasting...",

 xhtmlWaitScreenTitle : "XHTML",

 xhtmlWaitScreenText : "Converting to XHTML...",

 xhtmlDone : "XHTML conversion completed",

 htmlSourceChangedTitle : "Warning",

 htmlSourceChangedText : "The HTML source you entered might have been modified.",

 keyboardShortcutUndo_AccessKey : "Z",

 keyboardShortcutUndo_Ctrl : "t",

 keyboardShortcutUndo_Shift : "f",

 keyboardShortcutUndo_Alt : "f",

 keyboardShortcutRedo_AccessKey : "Y",

 keyboardShortcutRedo_Ctrl : "t",

 keyboardShortcutRedo_Shift : "f",

 keyboardShortcutRedo_Alt : "f",

 keyboardShortcutSelectAll_AccessKey : "A",

 keyboardShortcutSelectAll_Ctrl : "t",

 keyboardShortcutSelectAll_Shift : "f",

 keyboardShortcutSelectAll_Alt : "f",

 keyboardShortcutBold_AccessKey : "B",

 keyboardShortcutBold_Ctrl : "t",

 keyboardShortcutBold_Shift : "f",

 keyboardShortcutBold_Alt : "f",

 keyboardShortcutItalic_AccessKey : "I",

 keyboardShortcutItalic_Ctrl : "t",

 keyboardShortcutItalic_Shift : "f",

 keyboardShortcutItalic_Alt : "f",

 keyboardShortcutUnderline_AccessKey : "U",

 keyboardShortcutUnderline_Ctrl : "t",

 keyboardShortcutUnderline_Shift : "f",

 keyboardShortcutUnderline_Alt : "f",

 keyboardShortcutClearFormatting_AccessKey : " ",

 keyboardShortcutClearFormatting_Ctrl : "t",

 keyboardShortcutClearFormatting_Shift : "f",

 keyboardShortcutClearFormatting_Alt : "f",

 keyboardShortcutIndent_AccessKey : "M",

 keyboardShortcutIndent_Ctrl : "t",

 keyboardShortcutIndent_Shift : "f",

 keyboardShortcutIndent_Alt : "f",

 keyboardShortcutOutdent_AccessKey : "M",

 keyboardShortcutOutdent_Ctrl : "t",

 keyboardShortcutOutdent_Shift : "t",

 keyboardShortcutOutdent_Alt : "f",

 keyboardShortcutLeftAlign_AccessKey : "L",

 keyboardShortcutLeftAlign_Ctrl : "t",

 keyboardShortcutLeftAlign_Shift : "f",

 keyboardShortcutLeftAlign_Alt : "f",

 keyboardShortcutCenterAlign_AccessKey : "E",

 keyboardShortcutCenterAlign_Ctrl : "t",

 keyboardShortcutCenterAlign_Shift : "f",

 keyboardShortcutCenterAlign_Alt : "f",

 keyboardShortcutRightAlign_AccessKey : "R",

 keyboardShortcutRightAlign_Ctrl : "t",

 keyboardShortcutRightAlign_Shift : "f",

 keyboardShortcutRightAlign_Alt : "f",

 keyboardShortcutMakeHyperlink_AccessKey : "K",

 keyboardShortcutMakeHyperlink_Ctrl : "t",

 keyboardShortcutMakeHyperlink_Shift : "f",

 keyboardShortcutMakeHyperlink_Alt : "f",

 tablePreviewChar : "_",

 textStyleExampleText : "AaBbCcDdEeFfGgHhIiJjKkLlMm",

 reverting : "Reverting...",

 sending : "Sending...",

 emailDefaultBody : "Sample",

 saving : "Saving...",

 saved : "Saved",

 processingRequest : "Processing request...",

 deleting : "Deleting...",

 pageIsSiteHomePage : "This page is now the site homepage.",

 saveChangeDialogTitle : "Save Changes",

 saveChangeDialogDesc : "Do you want to save the changes you made to this page?",

 saveConflictStatusBarTitle : "Save Conflict:",

 saveFailed : "Cannot save the page.",

 buttonYes : "Yes",

 buttonNo : "No",

 buttonCancel : "Cancel",

 layoutsNotSupported : "This feature does not support the Layouts Editor.",

 dropdownImageAltText : "Dropdown",

 checkAltText : "Check",

 uncheckAltText : "Uncheck",

 editListItems : "Edit List Items",

 moreItems : "Not all items are shown...",

 dropdownLoading : "Loading...",

 getDataError : "This service isn't available right now.",

 getDataErrorRetry : "Click here to try again.",

 defaultViewDescription : "Default View",

 personalViewDescription : "Personal View",

 publicViewDescription : "Public View",

 moderationViewDescription : "Moderation View",

 close : "Close",

 restore : "Restore",

 maximize : "Maximize",

 dialogLoading : "Loading...",

 dialogLoadingText : "Please wait while the content loads.",

 hiddenButtonValueBeforeDialog : "Wrap focus to the end of the dialog",

 hiddenButtonValueAfterDialog : "Wrap focus to the beginning of the dialog",

 defaultDialogTitle : "Dialog",

 defaultDialogWidth : "768",

 defaultDialogHeight : "576",

 modelessDialogsNotImplemented : "Modeless dialogs are not implemented.",

 dialogCancelAK : "C",

 confirmWelcomePage : "If you make this page the home page for this site, users will no longer be able to see the old site home page. Do you want to set this page as this site's home page?",

 relationships_UnknownError : "Unknown Error.",

 relationships_RelatedFieldsFetchFailed : "Failed to retrieve related lists for this list.",

 relationships_DocLibHasNoRelatedLists : "The {0} document library does not have any related lists.",

 relationships_ListHasNoRelatedLists : "The {0} list does not have any related lists.",

 relationships_RelatedFetchFieldsTookTooLong : "A timeout occurred while retrieving related lists for this list.",

 relationships_ListFormsFetchFailed : "Failed to retrieve forms for list.",

 relationships_NoNewEditDisplayListForms : "This list does not contain any forms.",

 relationships_DefaultDisplayForm : "Default Display Form",

 relationships_DefaultNewForm : "Default New Form",

 relationships_DefaultEditForm : "Default Edit Form",

 relationships_CTForms : "Content Type Forms",

 relationships_CTDisplayForm : "({0}) Display Form",

 relationships_CTNewForm : "({0}) New Form",

 relationships_CTEditForm : "({0}) Edit Form",

 relationships_ToolTipTitle : "Insert Related Items Web Part",

 dlgTitleDel : "Delete Items",

 dlgTitleCheckin : "Check In Files",

 dlgTitleCheckout : "Check Out Files",

 dlgTitleError : "The server has encountered the following error(s):",

 errorDialogTitleText : "Error",

 genericLoading : "Loading...",

 webPartNotDisplay : "This web part cannot be displayed. Save and stop editing the page to see the web part.",

 viewGroupDefault : "Default",

 viewGroupPersonal : "Personal",

 viewGroupPublic : "Public",

 viewGroupModerated : "Moderated",

 viewGroupOther : "Other",

 modifyViewLabel : "Modify View",

 modifyInDesignerLabel : "Modify in SharePoint Designer (Advanced)",

 workflowSettingsLabel : "Workflow Settings",

 associateWorkflowLabel : "Add a Workflow",

 createWorkflowInDesignerLabel : "Create a Workflow in SharePoint Designer",

 createReUsableWorkflowInDesignerLabel : "Create a Reusable Workflow in SharePoint Designer",

 sendToOtherLocation : "Other Location",

 okButtonCaption : "OK",

 detailsView : "Details",

 thumbnailsView : "Thumbnails",

 filmstripView : "Filmstrip",

 modifyThisView : "Modify this view",

 createView : "Create view",

 editColEditable : "Editable",

 editColReadOnly : "Read Only",

 deleteText : "Delete",

 deleteFailed : "This item could not be deleted",

 requiredField : "This field requires a value.",

 serverCommError : "Unable to communicate with the server.",

 savingToServer : "Changes are currently being saved back to the server.  If you leave now, some of those changes may be lost.",

 changesHaveNotBeenSaved : "Changes have been made that have not yet been saved back to the server.  If you leave now, all of those changes will be lost.",

 docAlreadyExists : "The specified name is already in use.  A summary task cannot have the same name as another summary task in the current list.",

 ganttListName : "Project Tasks",

 createWaitScreenCancel : "Cancel",

 checkInComments : "Comments:",

 okButtonText : "OK",

 continueButtonText : "Continue",

 cancelButtonText : "Cancel",

 okCancelButtonWidth : "6em",

 alignRight : "right",

 pageStateCancelApprovalLabel : "Cancel Approval",

 pageStateDiscardCheckoutLabel : "Discard Check Out",

 pageStateDontSaveLabel : "Exit Without Saving",

 pageStateEditLabel : "Edit",

 pageStateSaveLabel : "Save",

 pageStateCheckinLabel : "Check In",

 pageStateCheckoutLabel : "Check Out",

 pageStateOverrideCheckoutLabel : "Override Check Out",

 pageStatePublishLabel : "Publish",

 pageStateSaveAndStopEditingLabel : "Save and Stop Editing",

 pageStateSubmitForApprovalLabel : "Submit for Approval",

 pageStateUnpublishLabel : "Unpublish",

 pageStateApproveLabel : "Approve",

 pageStateRejectLabel : "Reject",

 pageStateSaveBeforeNavigateUnknownError : "The page took too long to save. You can click "Cancel", and then try to save the page again. If you click "OK", you might lose unsaved data.",

 pageStateSaveBeforeNavigateNotCheckedOutWarning : "To save your changes before continuing, click "OK". To continue without saving changes, click "Cancel".",

 pageStateSaveBeforeNavigateLastChanceWarning : "You have made changes to your page that have not yet been saved. Are you sure you want to discard those changes?",

 tenantAdmin_SiteCollectionNewDialogTitle : "Create Site Collection",

 tenantAdmin_SiteCollectionDeleteDialogTitle : "Delete Site Collections",

 tenantAdmin_SiteCollectionPropertiesDialogTitle : "Site Collection Properties",

 tenantAdmin_SiteCollectionOwnersDialogTitle : "Site Collection Owners",

 tenantAdmin_SiteCollectionDiskQuotaDialogTitle : "Site Collection Disk Quota",

 rteDialog_Height : "175",

 rteDialog_Width : "400",

 renamePageDialog_Title : "Rename Page",

 webPartPageRecycleConfirmation : "Are you sure you want to send this page to the site Recycle Bin?",

 webPartPageDeleteConfirmation : "Are you sure you want to permanently delete this page?"

}

Some mighty fine messages ready for reuse...  I'll continue to post some more obscure things I'm finding as I dig deeper into the depths of sp.js.  

Monday, April 2, 2012

Modifying the default language in InfoPath

This will be a quick exercise on how to change the language you can write within InfoPath 2007...

Click on Form Options
Crack open your favorite form builder and then click on Tools.  From that menu, click on Programming on the left...  You should already know where I'm going with this.  Let's change that default (C#) to something nonsensical, unstructured and putrid; yet everyone seems to be jumping on the bandwagon: JavaScript or in this case JScript. Whatev...







(¸¸.♥➷♥•*¨)¸.•´¸.•*¨) ¸.•*¨)
(¸.•´(¸. ¸.•´¸.•*¨) ¸.♥➷•*¨)
─▀██▀─▄███▄─▀██─██▀██▀▀▀█─
──██─███─███─██─██─██▄█──conquers
──██─▀██▄██▀─▀█▄█▀─██▀█──all ♥➷♥
─▄██▄▄█▀▀▀─────▀──▄██▄▄▄█
¸.•´¸.•*¨) ¸♥.•*¨) (¸.•´¸♥➷♥¸.•´♥¸.•´♥¸.•*¨)♥.•*¨)¸.•*♥¸


Form Options



















(¸¸.♥➷♥•*¨)¸.•´¸.•*¨) ¸.•*¨)
(¸.•´(¸. ¸.•´¸.•*¨) ¸.♥➷•*¨)
─▀██▀─▄███▄─▀██─██▀██▀▀▀█─
──██─███─███─██─██─██▄█──conquers
──██─▀██▄██▀─▀█▄█▀─██▀█──all ♥➷♥
─▄██▄▄█▀▀▀─────▀──▄██▄▄▄█
¸.•´¸.•*¨) ¸♥.•*¨) (¸.•´¸♥➷♥¸.•´♥¸.•´♥¸.•*¨)♥.•*¨)¸.•*♥¸




I've decided from now on any InfoPath post will need something extra for me, so I can start to

░░░░░░░░░░░░▄▄
░░░░░░░░░░░█░░█
░░░░░░░░░░░█░░█
░░░░░░░░░░█░░░█
░░░░░░░░░█░░░░█
███████▄▄█░░░░░██████▄
▓▓▓▓▓▓█░░░░░░░░░░░░░░█
▓▓▓▓▓▓█░░░░░░░░░░░░░░█
▓▓▓▓▓▓█░░░░░░░░░░░░░░█
▓▓▓▓▓▓█░░░░░░░░░░░░░░█
▓▓▓▓▓▓█░░░░░░░░░░░░░░█
▓▓▓▓▓▓█████░░░░░░░░░█       
██████▀░░░░▀▀██████▀

it...

Want to see what damage I can do?  Stay tuned...

Monday, March 26, 2012

Get the ID of any SharePoint Wiki page

Hello _spPageContextInfo!!!
I found this little gem by viewing the source of my site spdwiki.com.  Simply running a console.dir() on this object reveals these properties:


  1. alertsEnabledtrue
  2. allowSilverlightPrompt"True"
  3. currentLanguage1033
  4. pageItemId1
  5. pageListId"{15d98081-a722-48ad-a30c-c25d4c31a228}"
  6. siteServerRelativeUrl"/"
  7. userId1
  8. webLanguage1033
  9. webServerRelativeUrl"/"
  10. webUIVersion4


I've noticed running this same inquiry on a different site, say http://www.sharepointfabian.com, the properties are different:


  1. alertsEnabledtrue
  2. allowSilverlightPrompt"True"
  3. currentLanguage1033
  4. pageListId"{a4668dd2-4dac-4cce-baf0-ddb1ea4f2d5e}"
  5. siteServerRelativeUrl"/"
  6. webLanguage1033
  7. webServerRelativeUrl"/blog"
  8. webUIVersion4


It's safe to say, this is because the latter is a blog and not a wiki.

What to make of all of this?  I'm able to display pertinent data accordingly and no longer required to rely on the text of the page name.

var pageID = _spPageContextInfo.pageItemId;

It's a much cleaner solution that just feels good.

I've been working on a commenting system for a SharePoint 2010 system.  Knowing some of these internal variables that are floating around is invaluable.  Hope you find this useful as well.

Yes Josh, I'm going to finish this finally. ;-)

Wednesday, March 21, 2012

Add Notepad++ to the context menu

This little regedit keeps coming in handy.  Thought I’d add it here so it’s easy for me to find and the other 2 of you that read this blog.

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell\Open with Notepad++\command]
@="\"C:\\Program Files (x86)\\Notepad++\\notepad++.exe\" \"%1\""

ContextMenuSave that into a file with the extension .reg and double click it to add to the registry.  You’ll now see Open with Notepad++ in the context menu.


Pretty awesome, eh?  You can add whatever else you like to your context menu as well.  As always though be cautious when modifying the registry.


I’ve seen people wreck, destroy, obliterate their machine fiddling with things they shouldn’t have.  With that said, have fun doing it!




This post was inspired by: http://www.sevenforums.com/software/29942-notepad-context-menu.html

Friday, March 2, 2012

roboCAML v0.4 has been released!

RoboCAMLYou may have seen me tweet about roboCAML the last few days.  If you were scratching your head about what it actually is, don’t feel bad.  No one knew…  It’s a jQuery module, *not* a plugin, I’ve built specifically to handle the tedious task of manually building CAML or worse hard coding CAML within your scripts.  An added benefit, is the ability to create dynamic CAML queries on the fly.

Currently
roboCAML has a depends on jQuery, but very well may become a  pure JavaScript module without any external dependencies.  It's hard to beat the $.ajax function within jQuery, but I'm willing to change based on feedback.  It’s all about the community, you know?

What does it do?

roboCAML takes away the pain of scripts that look like this:
     // #CAMLToggle doesn't exist, but this is here in case we want to give the user the ability to AND
     // or OR the PartNum
  var camlToggle = $("#CAMLToggle").val() ? $("#CAMLToggle").val() : "Or", 
   ddlSelected = false, 
   PartCat = [], 
   PartNum = [], 
   thisFieldRef = "", 
   camlQuery = "";
  
  $( "select.PartCat" ).each(function() {
   // Each select on the page has the PartCat class
   // the title attribute is also the name of the field for the CAML
   ctlTitle = $(this).attr("title");
   PartCat[ctlTitle] = ctlTitle;
   
   if ( ctlTitle ) != 0 ) {
    ddlSelected = true;
   }
  });
  
//First example of CAML engine
  i = 0;
  for (index in PartCat) {
   //console.log("Select title: " + i);
   //console.log("Select Val: " + PartCat[i]);
   if (PartCat[index] > 0) {
    thisFieldRef = "<Eq><FieldRef Name='" + index + "' LookupId='True' /><Value Type='Number'>" + PartCat[index] + "</Value></Eq>";
    if (i <= 1) {
     camlQuery += thisFieldRef;
    }
    if (i == 1) {
     camlQuery = "<And>" + camlQuery + "</And>";
    }
    if (i > 1) {
     camlQuery = "<And>" + camlQuery + thisFieldRef + "</And>";
    }
    i++;
   }
  }
//Show example of other CAML Engine
  
  $("input.PartNum:checked").each(function(index) {
   // If this isn't the first PartNum, we'll "wrap" the array with the camlToggle
   if(index > 0) {
    PartNum.unshift("<" + camlToggle + ">");
   }
   PartNum.push("<Eq><FieldRef Name='PartNum' LookupId='True' /><Value Type='Number'>" + $(this).attr("alt") + "</Value></Eq>");
   // If this isn't the first PartNum, we'll "wrap" the array with the camlToggle
   if(index > 0) {
    PartNum.push("</" + camlToggle + ">");
   }
  });
  
  // .join() defaults to commas, .join("") does the same thing. We'll join with a space, then replace
  // the spaces that fall between tags
  camlQuery += PartNum.join(" ").replace(/> </gi,"><");
  
  if ( $("input.PartNum:checked").length > 0 && ddlSelected ) {
   // If we have DDLs and PartNums, we'll <And> the two groups together, otherwise we won't
   camlQuery = "<And>" + camlQuery + "</And>";
  }
  camlQuery = "<Query><Where>" + camlQuery + "</Where><OrderBy><FieldRef Name='Title' Ascending='True' /></OrderBy></Query>";
  GetListItems(camlQuery);
 }


Within this script are two different ways to dynamically build CAML.  Each have their merits, but why do I have to think about setting up my CAML correctly and debugging it if I am having issues?  After being tasked to build a few of the complex scripts, sometimes several in a week, I had enough...  Time to roll up the sleeves and code a solution.  This is why I’ve built roboCAML, so now lets see what it does.

roboCAML In Action

roboCAML will assist in generating a string of useful CAML for use when making your Web Service or Client Object Model calls.  There are currently 5 methods available in roboCAML.

roboCAML.BatchCMD

So, now let’s look at roboCAML.BatchCMD method.  This method is a little tricky because there are three distinct actions you can take when using a batch.  Each requiring a different set of parameters.  In example 2.1, we’ll look at Deleting:
Example 2.1:
roboCAML.BatchCMD({
   batchCMD: 'Delete',
   IDs: [1,2,3]
});

This call accepts an array of ID’s and the “Delete” command.  The output will be:
<Batch OnError='Continue'><Method ID='3' Cmd='Delete'><Field Name='ID'>3</Field></Method><Method ID='2' Cmd='Delete'><Field Name='ID'>2</Field></Method><Method ID='1' Cmd='Delete'><Field Name='ID'>1</Field></Method></Batch> 
Now onto the New operation.  This example accepts the command for the batch.  What is different here from the Delete operation is, we can now pass in a valuePairs parameter.  This parameter accepts an array of arrays.  You’ll notice each array follows a certain pattern.  First the Static Name is provided and then the value.
Example: 2.2:
roboCAML.BatchCMD({ 
 batchCMD: "New",  
 valuePairs: [["PersonnelLookup", 1]]  //Static Column Name, Value
});

A more complex array would look like this:
roboCAML.BatchCMD({ 
 batchCMD: "New",  
 valuePairs: [["PersonnelLookup", 1, "ModuleNotes", "ModuleNotes", "Description", "Googly Glop"], ["ListUID", 3]]  //Static Column Name, Value
});

Which in turn produces:
<Batch OnError='Continue'><Method ID='1' Cmd='New'><Field Name='PersonnelLookup'>1</Field><Field Name='ModuleNotes'>ModuleNotes</Field><Field Name='Description'>Googly Glop</Field></Method><Method ID='2' Cmd='New'><Field Name='ListUID'>3</Field></Method></Batch> 
The last operation within roboCAML.BatchCMD is Update:

Example 2.3
roboCAML.BatchCMD({
 updates: [
  {
   //Notice batchCMD isn't present...
   //Static Column Name, Value
   valuePairs: ["Title", "Numero Tres", "PercentComplete", 1, "Boolean", 0, "ID", 3]
  },
  {
   //Defaults to Update anyway. No need to pass it.
   batchCMD: "Update",
   valuePairs: ["ID", 4, "Title", "Item4", "Boolean", 0]
  },
  {
   batchCMD: "New",
   valuePairs: ["Title", "Something New", "PercentComplete", 1]
  },
  {
   batchCMD: "Delete",
   ID: 6
  }
 ]
});

The output of the call above will generate:
<Batch OnError='Continue'>
 <Method ID='1' Cmd='Update'>
  <Field Name='Title'>Numero Tres</Field>
  <Field Name='PercentComplete'>1</Field>
  <Field Name='Boolean'>0</Field>
  <Field Name='ID'>3</Field>
 </Method>
 <Method ID='2' Cmd='Update'>
  <Field Name='ID'>4</Field>
  <Field Name='Title'>Item4</Field>
  <Field Name='Boolean'>0</Field>
 </Method>
 <Method ID='3' Cmd='New'>
  <Field Name='Title'>Something New</Field>
  <Field Name='PercentComplete'>1</Field>
 </Method>
 <Method ID='4' Cmd='Delete'>
  <Field Name='ID'>6</Field>
 </Method>
</Batch>

What’s very interesting with using the updates property of roboCAML.BatchCMD is the batch that is generated can be chocked full of all your different operations. Delete, New and Update all within one Web Service call. That’s #bada55.

roboCAML.OrderBy


And if you weren’t impressed by any of the above, maybe this will persuade you… It’s another snazzy way to build CAML on the fly. Here’s how to use roboCAML.OrderBy:

roboCAML.OrderBy({
 MyColumn: false,
 ID: true
});
Note: The value of each staticName can be a boolean or a string... The output of the call above will look like this:
<OrderBy><FieldRef Name='MyColumn' Ascending='False' /><FieldRef Name='ID' Ascending='True' /></OrderBy>

roboCAML.Query

Probably the most interesting method roboCAML has to offer.  There are a plethora of options within this method.  The best way to learn how to use this would be to read the docs or use the live demo.  Let’s look over a sample query you can use with roboCAML.
roboCAML.Query({
 listName: 'Calendar', 
 closeCaml: "Clientom",
 ViewFields: ["ID", "Created", "Title"],
 OrderBy: {
  ID: true
 },
 QueryOptions: {
  IncludeMandatoryColumns: false
 },
 config: [
  {
   filter: "&&",
   op: "*",
   staticName: "Title",
   value: "Daily"
  },
  {
   filter: "&&",
   op: "^",
   staticName: "Title",
   value: "Deleted"
  },
  {
   op: "!=",
   staticName: "ID",
   value: 3
  }
 ]
});


Since the CAML is not hardcoded, you can now easily generate whatever options needed to retrieve information from SharePoint.  Just like above in the “CAML Engines”, stuff an array full of info and do something with it...  I’m thinking of building a demo soon that will serve as a real world example of why this is useful for front-end development.


In case you were wondering, this is the output from heavy lifting done from roboCAML:



<View>
 <ViewFields>
  <FieldRef Name='Title' />
  <FieldRef Name='Created' />
  <FieldRef Name='ID' />
 </ViewFields>
 <Query>
  <Where>
   <And>
    <Contains>
     <FieldRef Name='Title' />
     <Value Type='Text'>Daily</Value>
    </Contains>
    <And>
     <BeginsWith>
      <FieldRef Name='Title' />
      <Value Type='Text'>Deleted</Value>
     </BeginsWith>
     <Neq>
      <FieldRef Name='ID' />
      <Value Type='Counter'>3</Value>
     </Neq>
    </And>
   </And>
  </Where>
  <OrderBy>
   <FieldRef Name='ID' Ascending='True' />
  </OrderBy>
 </Query>
 <IncludeMandatoryColumns>False</IncludeMandatoryColumns>
</View>

roboCAML.QueryOptions

This method will assist you in building queries and other various CAML fragments that you may need.  I haven’t found a comprehensive list that details all of the options available within this node.  The closest I’ve come to full documentation was on the Lists.GetListItems Method page within MSDN.  As I find/test/evaluate each new option I find, I’ll piecemeal them into the project. For now, the documentation can be found on the roboCAML project page.

roboCAML.ViewFields

As you could guess (if you are familiar with CAML), this does exactly what you would expect. Let’s take a look at roboCAML.ViewFields:


roboCAML.ViewFields(["Title", "Description", "ProjectName", "RelatedID"]);

This method accept an array of Static Names. The output will be:
<ViewFields><FieldRef Name='RelatedID' /><FieldRef Name='ProjectName' /><FieldRef Name='Description' /><FieldRef Name='Title' /></ViewFields> 
It’s just that simple… Really!

There you have it, roboCAML in a nutshell.  I’m missing some key parts that you *should* be able to do when creating CAML queries for SharePoint. I plan on adding them very soon!  Support for <Membership />, <Joins> (if it’s possible, haven’t tried yet...), and <ProjectedFields> are on top of my list as well as nested CAML fragments (Thanks Jim Bob!).  If you can think of anything you’d like to see added, feel free to ask