<div id="_conditional_formatting_link" style="display:none; ">
<div unselectable="on" style="display:inline-block; user-select:none; cursor:pointer; padding: 3px; background-color:#9b9b9b; color:white; border:1px solid #888;" onclick="javascript:var rules = document.getElementById('_conditional_formatting'); if(rules.style.display == 'none'){rules.style.display = 'inline-block'}else{rules.style.display = 'none'}">
Conditional Formatting
</div>
</div>
<div id="_conditional_formatting" style="display:none;background-color:#dfdfdf; border: 1px solid black; width:95%; max-width:1100px;">
<a style="border:0px;padding:5px;float:right;" title="Reapply Formatting" href="javascript:getConditions(false);">
<img style="border:0px;" src="/_layouts/images/staticrefresh.gif"/>
</a>
<ol id="_conditional_formatting_rules"></ol>
<div style="text-align:right; ">
<div id="_add_conditional_formatting_rule" unselectable="on" onclick="javascript: Add_Conditional_Formatting();" style="user-select:none; cursor:pointer; padding: 3px; margin: 3px; display:inline-block; background-color:#9b9b9b; border:1px solid #888; color:white;">Add Rule</div>
</div>
</div>
<script>
this.cfl = this.cfl ? this.cfl : new Object(null);
var conditionalFormattingList = "Conditional Formatting";
function getConditions(reloadRules) {
/* if reloadRules, query the conditions list and get all the rules. Otherwise just reapply the ones in memory to the current document. */
if (typeof reloadRules == "undefined") { reloadRules = true; }
if (reloadRules) {
var conditionalFormattingRules = document.getElementById("_conditional_formatting_rules");
while (conditionalFormattingRules.children.length > 0) { /* Clear out the currently displayed list of rules. */
conditionalFormattingRules.removeChild(conditionalFormattingRules.children[0]);
}
this.cfl.clientContext = new SP.ClientContext();
this.cfl.user = cfl.clientContext.get_web().get_currentUser();
var list = cfl.clientContext.get_web().get_lists().getByTitle(conditionalFormattingList);
var camlQuery = new SP.CamlQuery();
var folder = list.get_rootFolder();
camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'URL\' /><Value Type=\'Text\'>' + document.location.pathname + '</Value></Eq></Where><OrderBy><FieldRef Name=\'Priority\' /><FieldRef Name=\'Name\' /></OrderBy></Query></View>');
this.cfl.items = list.getItems(camlQuery);
cfl.clientContext.load(cfl.user);
cfl.clientContext.load(list, 'EffectiveBasePermissions');
cfl.clientContext.load(cfl.items);
cfl.clientContext.load(folder);
}
this.cfl.clientContext.executeQueryAsync(
Function.createDelegate(this,
function () {
var Me = this.cfl.user.get_title();
if (reloadRules) {
var baseFormUrl = folder.get_serverRelativeUrl() + "/EditForm.aspx?ID=";
/* Figure out if the current user has access to create or edit items on the Conditional Formatting list */
var perms = list.get_effectiveBasePermissions();
this.cfl.hasEdit = perms.has(SP.PermissionKind.editListItems);
this.cfl.hasCreate = perms.has(SP.PermissionKind.addListItems);
/* Fill an array with our formatting rules */
this.cfl.targets = [];
var itemEnumerator = this.cfl.items.getEnumerator();
while (itemEnumerator.moveNext()) {
var item = itemEnumerator.get_current();
var targ = new Object(null);
targ.column = item.get_item("Column");
targ.comparison = item.get_item("Comparison");
targ.style = item.get_item("Style");
targ.scope = item.get_item("Scope");
targ.type = item.get_item("Type");
targ.value = item.get_item("Value"); if (targ.value == null) { targ.value = ""; }
targ.id = item.get_item("ID");
targ.offset = item.get_item("Offset");
cfl.targets.push(targ);
}
}
if (!this.cfl.hasCreate) { document.getElementById("_add_conditional_formatting_rule").style.display = "none"; }
for (var targetIterator = 0, len = cfl.targets.length; targetIterator < len; targetIterator++) {
var currentTarget = cfl.targets[targetIterator];
if (reloadRules) {
var rulelist = document.getElementById("_conditional_formatting_rules");
var ruletoadd = document.createElement("li");
var comparisondisplay = currentTarget.type.indexOf("Field") != -1 ? "value of the <b>" + currentTarget.value + "</b> column" : "<b>'" + currentTarget.value + "'</b>";
if (currentTarget.type == "Special" || currentTarget.type == "Number") {
if (currentTarget.value.toString().toLowerCase() == "[me]") { comparisondisplay = "<b>[Me](" + Me + ")</b>"; }
else { comparisondisplay = "<b>" + currentTarget.value + "</b>"; }
}
if (currentTarget.value == "") { comparisondisplay = "<b>(blank)</b>"; }
if (currentTarget.offset != null) {
comparisondisplay += "<b>" + (currentTarget.offset < 0 ? " " : " +") + currentTarget.offset + "</b>"
}
var editLink = this.cfl.hasEdit ? "<div style='display:inline-block;cursor:pointer;' onclick='SP.UI.ModalDialog.commonModalDialogOpen(" + '"' + baseFormUrl + currentTarget.id + '&Source=' + document.location.pathname + '"' + ",{},refreshPageConditions); '>" + "<img src='/_layouts/images/EDITITEM.GIF' style='vertical-align:middle;' title='Customize' alt='Customize'/>" + " </div>" : "";
ruletoadd.innerHTML = editLink + "When <b>" + currentTarget.column + "</b> "
+ currentTarget.comparison + " " + comparisondisplay
+ ", apply {" + (currentTarget.style == null ? "remove all formatting" : "<span style='" + currentTarget.style + "'>" + currentTarget.style + "</span>") + "} to the <b>" + currentTarget.scope + "</b>" + ((currentTarget.scope != "Cell" && currentTarget.scope != "Row") ? " column" : "");
rulelist.appendChild(ruletoadd);
}
var tables = document.querySelectorAll("table.ms-listviewtable"); /* Should get all the list view web parts on the page. */
var t_i = 0;
while (t_i < tables.length) {
var columnIndex = null; /* Index of the column to compare against */
var valueIndex = null; /* Index of a second column from which to pull the value to compare */
var styleTargetIndex = null; /* Index of a column to apply formatting to */
var thisTable = tables[t_i];
var headings = thisTable.rows[0].cells;
var h_i = 0;
while (h_i < headings.length) { /* Check all the column headings... */
var thisHeading = headings[h_i].querySelector("div:first-child");
if (thisHeading != null) {
/* In Internet Explorer, the headings have a DisplayName attribute you can grab. If that's not there, just grab the innerText or textContent */
var dispname = thisHeading.DisplayName ? thisHeading.DisplayName : (thisHeading.innerText ? thisHeading.innerText : thisHeading.textContent);
dispname = dispname.replace(/^\s+|\s+$/g, '');/* removes leading and trailing whitespace */
if (currentTarget.scope != "Cell" && currentTarget.scope != "Row") {
/*If the scope isn't Cell or Row, see if this is the cell to which the formatting should applied */
if (dispname == currentTarget.scope) { styleTargetIndex = h_i; }
}
if (currentTarget.type.indexOf("Field") != -1) {
/*If the value type is a Field, check to see if this is the field whose value we care about */
if (dispname == currentTarget.value.toString()) { valueIndex = h_i; }
}
if (dispname == currentTarget.column) { columnIndex = h_i; }
}
h_i += 1;
}
if (columnIndex != null) { /* If we found a matching heading, let's try to apply the rules... */
var rows = thisTable.rows;
for (var i = (rows.length > 0 ? 1 : 0) ; i < rows.length; i++) {
var cells = rows[i].children;
if (cells.length <= columnIndex) { continue }
var innerLink = cells[columnIndex].querySelector("a"); /* I want to specifically target links so that we can change their text color if necessary */
/* Populate valueToEval with the text value of the current cell, or its inner link if it has one */
var valueToEval = cells[columnIndex].innerText ? (innerLink != null ? innerLink.innerText : cells[columnIndex].innerText) : (innerLink != null ? innerLink.textContent : cells[columnIndex].textContent);
if (typeof (valueToEval) == "undefined") { valueToEval = "" } /* Treat empties as blanks */
var listValueToCompareAgainst = null;
if (valueIndex != null) { /* valueIndex only has a value if we need to grab the comparison value from another column on the list */
valueLink = cells[valueIndex].querySelector("a");
listValueToCompareAgainst = cells[valueIndex].innerText ? (valueLink != null ? valueLink.innerText : cells[valueIndex].innerText) : (valueLink != null ? valueLink.textContent : cells[valueIndex].textContent);
}
var needsStyling = false;
switch (currentTarget.type) {
case "Number":
if (!isNaN(Number(valueToEval))) {
valueToEval = +(valueToEval);
}
if (!isNaN(Number(currentTarget.value))) {
currentTarget.value = +(currentTarget.value);
}
break;
case "Date":
valueToEval = new Date(valueToEval);
currentTarget.value = new Date(currentTarget.value);
if (currentTarget.offset != null) {
currentTarget.value.setDate(currentTarget.value.getDate() + +(currentTarget.offset));
}
break;
case "Text": /* Already covered, bro */ break;
case "Date Field":
valueToEval = new Date(valueToEval);
currentTarget.value = new Date(listValueToCompareAgainst);
if (currentTarget.offset != null) {
currentTarget.value.setDate(currentTarget.value.getDate() + +(currentTarget.offset));
}
break;
case "Text Field": currentTarget.value = listValueToCompareAgainst; break;
case "Number Field":
if (!isNaN(Number(listValueToCompareAgainst))) {
currentTarget.value = listValueToCompareAgainst;
if (currentTarget.offset != null) {
currentTarget.value += Number(currentTarget.offset);
}
}
if (!isNaN(Number(valueToEval))) {
valueToEval = Number(valueToEval);
}
break;
case "Special":
if (currentTarget.value.toLowerCase) {
if (currentTarget.value.toLowerCase() == "[me]") { currentTarget.value = Me }
else if (currentTarget.value.toLowerCase().indexOf("[today]") != -1) {
var dateDifference = Number(currentTarget.value.toLowerCase().replace("[today]", "").replace(" ", "").replace("+", ""));
currentTarget.value = new Date();
if (!isNaN(dateDifference)) { currentTarget.value.setDate(currentTarget.value.getDate() + dateDifference); }
if (currentTarget.offset != null) {
currentTarget.value.setDate(currentTarget.value.getDate() + Number(currentTarget.offset));
}
valueToEval = new Date(valueToEval);
}
} else { valueToEval = new Date(valueToEval); }
break;
}
switch (currentTarget.comparison) {
case "Greater Than or Equal To": needsStyling = (valueToEval >= currentTarget.value); break;
case "Greater Than": needsStyling = (valueToEval > currentTarget.value); break;
case "Less Than or Equal To": needsStyling = (valueToEval <= currentTarget.value); break;
case "Less Than": needsStyling = (valueToEval < currentTarget.value); break;
case "Equal To": needsStyling = (valueToEval == currentTarget.value); break;
case "Not Equal To": needsStyling = (valueToEval != currentTarget.value); break;
case "Contains": needsStyling = (valueToEval.indexOf(currentTarget.value) != -1); break;
case "Does Not Contain": needsStyling = (valueToEval.indexOf(currentTarget.value) == -1); break;
}
if (needsStyling) {
var links;
if (currentTarget.scope != "Row") {
var targetIndex = (styleTargetIndex != null) ? styleTargetIndex : columnIndex;
cells[targetIndex].setAttribute("style", currentTarget.style);
links = cells[targetIndex].querySelectorAll("a");
} else {
rows[i].setAttribute("style", currentTarget.style);
for (var j = 0; j < cells.length; j++) {
cells[j].setAttribute("style", currentTarget.style);
}
links = rows[i].querySelectorAll("a");
}
for (var j = 0; j < links.length; j++) {
if (links[j].title != "Open Menu") {
links[j].setAttribute("style", currentTarget.style);
links[j].style.backgroundColor = "";
}
links[j].style.border = "0px";
}
}
}
}
t_i += 1;
}
}
document.getElementById("_conditional_formatting_link").style.display = "inline-block";
}
),
Function.createDelegate(this,
function (sender, args) { /* There was an error accessing the list. Time to create it! */
var lci = new SP.ListCreationInformation();
lci.set_title(conditionalFormattingList);
lci.set_templateType(SP.ListTemplateType.genericList);
var condition_list = clientContext.get_web().get_lists().add(lci);
clientContext.load(condition_list);
var colTitle = condition_list.get_fields().getByTitle("Title");
colTitle.set_required(false); colTitle.set_hidden(true); colTitle.update();
condition_list.update();
var colColumn = condition_list.get_fields().addFieldAsXml('<Field Description=\'The column to compare (must be visible on the page)\' DisplayName=\'Column\' Type=\'Text\'/>', true, SP.AddFieldOptions.defaultValue);
var colComparison = condition_list.get_fields().addFieldAsXml('<Field Description=\'\' Type=\'Choice\' DisplayName=\'Comparison\' Format=\'Dropdown\' FillInChoice=\'FALSE\'><Default>Equal To</Default><CHOICES><CHOICE>Greater Than</CHOICE><CHOICE>Greater Than or Equal To</CHOICE><CHOICE>Equal To</CHOICE><CHOICE>Less Than or Equal To</CHOICE><CHOICE>Less Than</CHOICE><CHOICE>Not Equal To</CHOICE><CHOICE>Contains</CHOICE><CHOICE>Does Not Contain</CHOICE></CHOICES></Field>', true, SP.AddFieldOptions.defaultValue);
var colValue = condition_list.get_fields().addFieldAsXml('<Field Description=\'The value or the name of a column to compare against\' DisplayName=\'Value\' Type=\'Text\'/>', true, SP.AddFieldOptions.defaultValue);
var colType = condition_list.get_fields().addFieldAsXml('<Field Description=\'Indicate the type of value you are comparing against. Choose Special if using the [Me] or [Today] placeholders.\' Type=\'Choice\' DisplayName=\'Type\' Format=\'Dropdown\' FillInChoice=\'FALSE\'><Default>Text</Default><CHOICES><CHOICE>Date</CHOICE><CHOICE>Number</CHOICE><CHOICE>Text</CHOICE><CHOICE>Date Field</CHOICE><CHOICE>Number Field</CHOICE><CHOICE>Text Field</CHOICE><CHOICE>Special</CHOICE></CHOICES></Field>');
var colOffset = condition_list.get_fields().addFieldAsXml('<Field Description=\'Optionally specify a number to offset the value by when comparing against a number or date.\' DisplayName=\'Offset\' Type=\'Number\' />', true, SP.AddFieldOptions.defaultValue);
var colStyle = condition_list.get_fields().addFieldAsXml('<Field NumLines=\'4\' Description=\'The CSS to apply to when the condition is met. Leave blank to remove formatting. Example syntax: background-color:darkred; color:white; font-weight:bold;\' DisplayName=\'Style\' Type=\'Note\' />', true, SP.AddFieldOptions.defaultValue);
var colScope = condition_list.get_fields().addFieldAsXml('<Field Description=\'The scope to which the style should be applied. Choose Row, Cell, or specify a column name.\' Type=\'Choice\' DisplayName=\'Scope\' Format=\'Dropdown\' FillInChoice=\'TRUE\'><Default>Cell</Default><CHOICES><CHOICE>Cell</CHOICE><CHOICE>Row</CHOICE></CHOICES></Field>', true, SP.AddFieldOptions.defaultValue);
var colPriority = condition_list.get_fields().addFieldAsXml('<Field Description=\'Priority determines which styles are applied in case of overlapping conditions. Higher numbers are applied later.\' DisplayName=\'Priority\' Type=\'Number\' />', true, SP.AddFieldOptions.defaultValue);
var colUrl = condition_list.get_fields().addFieldAsXml('<Field Description=\'Page where this rule should be applied\' DisplayName=\'URL\' Type=\'Text\'/>', true, SP.AddFieldOptions.defaultValue);
clientContext.executeQueryAsync(
Function.createDelegate(this, function () { getConditions(); }),
Function.createDelegate(this, function (sender, args) { document.getElementById("_conditional_formatting").innerHTML = ("An error occcurred while trying to apply conditional formatting to the list for you. Error details: " + args.get_message() + " " + args.get_stackTrace()); document.getElementById("_conditional_formatting_link").style.display = "inline-block"; }));
}
));
}
/* This method is called when the Add Rule button is clicked. */
function Add_Conditional_Formatting() {
/* Create a new item with only the URL and Priority fields filled out */
var currUrl = document.location.pathname;
var clientContext = new SP.ClientContext();
var itemCreateInfo = new SP.ListItemCreationInformation();
var newItem = clientContext.get_web().get_lists().getByTitle(conditionalFormattingList).addItem(itemCreateInfo);
newItem.set_item('URL', currUrl);
/* Give the new item a priority that will put it at the end of the list. This is kind of a hack since the highest priority is not necessarily the rulecount. */
newItem.set_item('Priority', document.getElementById("_conditional_formatting_rules").children.length + 1);
newItem.update();
clientContext.load(newItem);
clientContext.executeQueryAsync(Function.createDelegate(this, function () {
getConditions(); /* Reload to refresh the rules list after adding the item */
}), Function.createDelegate(this, function (sender, args) { alert(args.get_message()); }));
}
/* This method is called when the Edit Item dialog box is closed. It refreshes the page it the item was saved. */
function refreshPageConditions(result) { if (result != SP.UI.DialogResult.cancel) { window.location.replace(document.location.href) } }
ExecuteOrDelayUntilScriptLoaded(function () {
getConditions();
/* If there are any collapsible sections on the page, keep checking to see whether formatting needs to be reapplied */
this.cfl.TableRowCount = 0;
if (document.querySelector("img[alt='expand']") != null) {
setInterval(function () {
var tempTableRowCount = document.querySelectorAll("tr").length;
if (tempTableRowCount != this.cfl.TableRowCount) {
/* Only reapply formatting if the count of table rows is different than it was previously */
this.cfl.TableRowCount = tempTableRowCount;
getConditions(false) /* Passing false reapplies loaded rules without re-querying the SharePoint list */
}
}, 1000)
}
}, "SP.JS");
</script>