rantings and ravings of a technology based solutionist

Preparing for an AngularJS AdSense and SEO Friendly Site

As I developed www.thepersonalfinancecenter.com with the joy of using AngularJS coupled with an Azure Mobile Services backend, the struggle was not with implementing a voting feature for social authority or providing identity management (thanks to Auth0), but rather how to ensure that AdSense would render properly and the site could be SEO compliant. Let’s address these separately.

AdSense and AngularJS
Since AngularJS normally acts as a Single Page Application, AdSense Ads could not be placed within Views. This created a challenge as after a few navigations on the site, the Ads would go away since AdSense saw it as one page going beyond the max of 3 Ads. I had to alter the design to have the Ads at the index.html layer housing the Views that would get routed to. For the visitor, the same Ads would stay constant through their visit, but this is a small price to pay versus no Ads!

SEO and AngularJS
While this can, and may end up, being several posts… one of the most critical aspects of SEO and AngularJS that I have found is to use a prerenderer to display static versions of your Views/pages. This was especially true in my case, since the majority of my content is retrieved via Mobile Web Services and displayed thru JavaScript. To be clear, this is much more of a JavaScript issue than a AngularJS challenge. If I had 1,000 hard coded views with plain HTML content I may not need a prerenderer.

In the end, I went with ajaxsnapshots.com/ since it had the clearest directions for integrating with IIS. Prerender.io is another strong option and integrates nicely with Node.js.

In short, if you are pursuing an AngularJS site with AdSense and SEO in mind, consider that AdSense may impact some of your design choices and that a good prerenderer is a must have with dynamic content.

Microsoft removes MicrosoftAjax.js from SharePoint/Tells No One (Yet)

If you are one of the multitude of users/developers who depend on MicrosoftAjax.js via accessing it in the _layouts/15 or _layouts/ directory and found that it is now gone from your SharePoint Online tenant or local SharePoint instance, you are not alone. Microsoft deemed this unnecessary as they believed it was not in use except for legacy Excel needs. In reality, many of us depend on it for client side operations.

After conversations with Microsoft this week, they stated that a KB Article and solution will be posted in the near future but that using the CDN for MicrosoftAjax.js is acceptable. I would recommend downloading the script from the CDN and referencing it locally in case of CDN issues. The CDN is located here: https://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js  

UPDATE: After Microsoft worked internally and realized the impact, they have begun rolling back this change and restored MicrosoftAjax.js to tenants. Check to ensure yours is restored. If not, use the method above.

Edit HTML, CSS, and JavaScript Files in the Cloud using OneDrive with IntelliSense

As I was swapping in some Web design files to OneDrive, I clicked and opened a file to find that it went straight into an edit mode. Curious to see if I could truly edit the file, I found that not only could I edit it, but it included IntelliSense! This replaced the need to have Visual Studio installed on my machine for some of my code needs.

While I couldn’t preview the changes from OneDrive, it is easy enough to download the directory to a desktop or other preferred location and click on the “Index” or home file to start browsing through the Web site.

See an example of the edit view below:


The Budget Calculator: Responsive Web Design Example

While The Budget Calculator offers a “Free Budget Calculator to get control of your spending and start planning for the future today”, it gave me an excuse to play with Bootstrap 3 with a focus on aligning inputs responsively. Specifically the Grid System employed by Bootstrap provides greater stability/flexibility versus traditional percentage based responsive site design. As far as dealing with inputs, there are a lot of styling options which I encourage others to evaluate first before pursuing your own customizations. Per the core Bootstrap CSS, I kept it intact and used a second file for non-Bootstrap customizations.

Bootstrap can be found at: http://getbootstrap.com

The Budget Calculator can be found at: http://www.thebudgetcalculator.com

SharePoint URLs for Administrators

If you have ever struggled to find the Site Settings in a site with a custom design, or the Web Part Gallery, the folks at Fpweb.net have compiled a very useful list of SharePoint URLs. Please find it at: http://blog.fpweb.net/your-sharepoint-url-list-an-administrators-guid/

Know Your Limits: Capacity planning for Hyper-V Virtual Machines in Server 2012

This is a follow up to the previous post for Server 2008 R2 (http://thebitsthatbyte.com/know-your-limits-capacity-planning-for-hyper-v-virtual-machines/) and provides limits for Virtual Machines running within Hyper-V on Server 2012.

You will notice that the differences are quite stunning, especially surrounding the amount of Virtual Processors, Memory, and Hard Disk Capacity (if using VHDX format). Full details can be found on the Microsoft page here: http://technet.microsoft.com/en-us/library/jj680093.aspx

Component Maximum Notes
Virtual processors 64 The number of virtual processors supported by a guest operating system might be lower. For more information, see the Hyper-V Overview.
Memory 1 TB Review the requirements for the specific operating system to determine the minimum and recommended amounts.
Virtual hard disk capacity 64 TB supported by the VHDX format introduced in Windows Server 2012 and Windows® 8; 2040 GB supported by the VHD format. Each virtual hard disk is stored on physical media as either a .vhdx or a .vhd file, depending on the format used by the virtual hard disk.
Virtual IDE disks 4 The startup disk (sometimes referred to as the boot disk) must be attached to one of the IDE devices. The startup disk can be either a virtual hard disk or a physical disk attached directly to a virtual machine.
Virtual SCSI controllers 4 Use of virtual SCSI devices requires integration services to be installed in the guest operating system. For a list of the guest operating systems for which integration services are available, see the Hyper-V Overview.
Virtual SCSI disks 256 Each SCSI controller supports up to 64 disks, which means that each virtual machine can be configured with as many as 256 virtual SCSI disks. (4 controllers x 64 disks per controller)
Virtual Fibre Channel adapters 4 As a best practice, we recommended that you connect each virtual Fibre Channel Adapter to a different virtual SAN.
Size of physical disks attached directly to a virtual machine Varies Maximum size is determined by the guest operating system.
Snapshots 50 The actual number may be lower, depending on the available storage. Each snapshot is stored as an .avhd file that consumes physical storage.
Virtual network adapters 12
  • 8 can be the “network adapter” type. This type provides better performance and requires a virtual machine driver that is included in the integration services packages.
  • 4 can be the “legacy network adapter” type. This type emulates a specific physical network adapter and supports the Pre-execution Boot Environment (PXE) to perform network-based installation of an operating system.
Virtual floppy devices 1 virtual floppy drive None.
Serial (COM) ports 2 None.

Free SharePoint Training by Microsoft

Here are three free SharePoint training resources from Microsoft that are often overlooked. So before you jump to Lynda or Pluralsight, check these out. Enjoy!

Microsoft SharePoint Help:


Channel 9 Videos:


Microsoft Virtual Academy:


Switch SharePoint 2013 Page Language to User Preferred Language using JavaScript/jQuery

When users set their language preferences within their My Site, many expect translation to occur across all of SharePoint. The reality is that this will change certain aspects of SharePoint, but not page text or content within custom Web Parts. While the multi-lingual aspects of SharePoint 2013 are robust (variations, machine translation, etc.), there is a core limitation that affects the switch to the user language.

If you open the developer tools in IE, you will find that SharePoint sets the page language to English (ex. html lang=”en-US”) by default even if your preferred language is different. This is highly problematic if you, for example, serve up both English and Spanish content to one page and only show the content via the language you want. This requires some CSS tagging, but is a nice option versus a full site variation.

To accomplish the switch, I developed the following script, which can be run via the XML Viewer Web Part method mentioned here. This script provides a dictionary of key/value pairs for each LCID referenced by Microsoft, detects the users preferred language, appends an ID to the core <html> tag for reference, and then changes to the preferred language. All of these activities occur post DOM load, as the default language tag of “en-US” needs to be set first.

¡buena suerte!

HTML file/code to be referenced by XML Viewer Web Part (I placed the JavaScript and HTML file in SiteAssets):

<?xmlversion="1.0"encoding="utf-8"?> <!--Supporting JavaScript Files--> <scriptsrc="../SiteAssets/switchLanguage.js"></script>

JavaScript file/code referenced by HTML file:

SP.SOD.executeFunc("sp.js", 'SP.ClientContext', switchLanguage);
function switchLanguage() {     var language = {         54: 'af',         1078: 'af-ZA',         28: 'sq',         1052: 'sq-AL',         132: 'gsw',         1156: 'gsw-FR',         94: 'am',         1118: 'am-ET',         1: 'ar',         5121: 'ar-DZ',         15361: 'ar-BH',         3073: 'ar-EG',         2049: 'ar-IQ',         11265: 'ar-JO',         13313: 'ar-KW',         12289: 'ar-LB',         4097: 'ar-LY',         6145: 'ar-MA',         8193: 'ar-OM',         16385: 'ar-QA',         1025: 'ar-SA',         10241: 'ar-SY',         7169: 'ar-TN',         14337: 'ar-AE',         9217: 'ar-YE',         43: 'hy',         1067: 'hy-AM',         77: 'as',         1101: 'as-IN',         29740: 'az-Cyrl',         2092: 'az-Cyrl-AZ',         44: 'az',         30764: 'az-Latn',         1068: 'az-Latn-AZ',         69: 'bn',         2117: 'bn-BD',         1093: 'bn-IN',         109: 'ba',         1133: 'ba-RU',         45: 'eu',         1069: 'eu-ES',         35: 'be',         1059: 'be-BY',         25626: 'bs-Cyrl',         8218: 'bs-Cyrl-BA',         26650: 'bs-Latn',         30746: 'bs',         5146: 'bs-Latn-BA',         126: 'br',         1150: 'br-FR',         2: 'bg',         1026: 'bg-BG',         85: 'my',         1109: 'my-MM',         3: 'ca',         1027: 'ca-ES',         146: 'ku',         31890: 'ku-Arab',         1170: 'ku-Arab-IQ',         92: 'chr',         31836: 'chr-Cher',         1116: 'chr-Cher-US',         4: 'zh-Hans',         30724: 'zh',         2052: 'zh-CN',         4100: 'zh-SG',         31748: 'zh-Hant',         3076: 'zh-HK',         5124: 'zh-MO',         1028: 'zh-TW',         131: 'co',         1155: 'co-FR',         26: 'bs, hr, or sr',         1050: 'hr-HR',         4122: 'hr-BA',         5: 'cs',         1029: 'cs-CZ',         6: 'da',         1030: 'da-DK',         140: 'prs',         1164: 'prs-AF',         101: 'dv',         1125: 'dv-MV',         19: 'nl',         2067: 'nl-BE',         1043: 'nl-NL',         9: 'en',         3081: 'en-AU',         10249: 'en-BZ',         4105: 'en-CA',         9225: 'en-029',         15369: 'en-HK',         16393: 'en-IN',         6153: 'en-IE',         8201: 'en-JM',         17417: 'en-MY',         5129: 'en-NZ',         13321: 'en-PH',         18441: 'en-SG',         7177: 'en-ZA',         11273: 'en-TT',         2057: 'en-GB',         1033: 'en-US',         12297: 'en-ZW',         37: 'et',         1061: 'et-EE',         56: 'fo',         1080: 'fo-FO',         100: 'fil',         1124: 'fil-PH',         11: 'fi',         1035: 'fi-FI',         12: 'fr',         2060: 'fr-BE',         11276: 'fr-CM',         3084: 'fr-CA',         9228: 'fr-CD',         12300: 'fr-CI',         1036: 'fr-FR',         15372: 'fr-HT',         5132: 'fr-LU',         13324: 'fr-ML',         14348: 'fr-MA',         6156: 'fr-MC',         8204: 'fr-RE',         10252: 'fr-SN',         4108: 'fr-CH',         98: 'fy',         1122: 'fy-NL',         103: 'ff',         31847: 'ff-Latn',         2151: 'ff-Latn-SN',         86: 'gl',         1110: 'gl-ES',         55: 'ka',         1079: 'ka-GE',         7: 'de',         3079: 'de-AT',         1031: 'de-DE',         5127: 'de-LI',         4103: 'de-LU',         2055: 'de-CH',         8: 'el',         1032: 'el-GR',         111: 'kl',         1135: 'kl-GL',         116: 'gn',         1140: 'gn-PY',         71: 'gu',         1095: 'gu-IN',         104: 'ha',         31848: 'ha-Latn',         1128: 'ha-Latn-NG',         117: 'haw',         1141: 'haw-US',         13: 'he',         1037: 'he-IL',         57: 'hi',         1081: 'hi-IN',         14: 'hu',         1038: 'hu-HU',         15: 'is',         1039: 'is-IS',         112: 'ig',         1136: 'ig-NG',         33: 'id',         1057: 'id-ID',         93: 'iu',         31837: 'iu-Latn',         2141: 'iu-Latn-CA',         30813: 'iu-Cans',         1117: 'iu-Cans-CA',         60: 'ga',         2108: 'ga-IE',         16: 'it',         1040: 'it-IT',         2064: 'it-CH',         17: 'ja',         1041: 'ja-JP',         4096: 'jv',         4096: 'jv-Latn',         4096: 'jv-Latn-ID',         134: 'qut',         1158: 'qut-GT',         75: 'kn',         1099: 'kn-IN',         63: 'kk',         1087: 'kk-KZ',         83: 'km',         1107: 'km-KH',         135: 'rw',         1159: 'rw-RW',         65: 'sw',         1089: 'sw-KE',         87: 'kok',         1111: 'kok-IN',         18: 'ko',         1042: 'ko-KR',         64: 'ky',         1088: 'ky-KG',         84: 'lo',         1108: 'lo-LA',         38: 'lv',         1062: 'lv-LV',         39: 'lt',         1063: 'lt-LT',         31790: 'dsb',         2094: 'dsb-DE',         110: 'lb',         1134: 'lb-LU',         47: 'mk',         1071: 'mk-MK',         4096: 'mg',         4096: 'mg-MG',         62: 'ms',         2110: 'ms-BN',         1086: 'ms-MY',         76: 'ml',         1100: 'ml-IN',         58: 'mt',         1082: 'mt-MT',         129: 'mi',         1153: 'mi-NZ',         122: 'arn',         1146: 'arn-CL',         78: 'mr',         1102: 'mr-IN',         124: 'moh',         1148: 'moh-CA',         80: 'mn',         30800: 'mn-Cyrl',         1104: 'mn-MN',         31824: 'mn-Mong',         2128: 'mn-Mong-CN',         4096: 'nqo',         4096: 'nqo-GN',         97: 'ne',         2145: 'ne-IN',         1121: 'ne-NP',         20: 'no',         31764: 'nb',         1044: 'nb-NO',         30740: 'nn',         2068: 'nn-NO',         130: 'oc',         1154: 'oc-FR',         72: 'or',         1096: 'or-IN',         114: 'om',         1138: 'om-ET',         99: 'ps',         1123: 'ps-AF',         41: 'fa',         1065: 'fa-IR',         21: 'pl',         1045: 'pl-PL',         22: 'pt',         4096: 'pt-AO',         1046: 'pt-BR',         2070: 'pt-PT',         1281: 'qps-ploc',         1534: 'qps-ploca',         2559: 'qps-plocm',         70: 'pa',         31814: 'pa-Arab',         1094: 'pa-IN',         2118: 'pa-Arab-PK',         107: 'quz',         1131: 'quz-BO',         2155: 'quz-EC',         3179: 'quz-PE',         24: 'ro',         2072: 'ro-MD',         1048: 'ro-RO',         23: 'rm',         1047: 'rm-CH',         25: 'ru',         1049: 'ru-RU',         133: 'sah',         1157: 'sah-RU',         28731: 'smn',         9275: 'smn-FI',         31803: 'smj',         4155: 'smj-NO',         5179: 'smj-SE',         59: 'se',         3131: 'se-FI',         1083: 'se-NO',         2107: 'se-SE',         29755: 'sms',         8251: 'sms-FI',         30779: 'sma',         6203: 'sma-NO',         7227: 'sma-SE',         79: 'sa',         1103: 'sa-IN',         145: 'gd',         1169: 'gd-GB',         27674: 'sr-Cyrl',         7194: 'sr-Cyrl-BA',         12314: 'sr-Cyrl-ME',         10266: 'sr-Cyrl-RS',         3098: 'sr-Cyrl-CS',         28698: 'sr-Latn',         31770: 'sr',         6170: 'sr-Latn-BA',         11290: 'sr-Latn-ME',         9242: 'sr-Latn-RS',         2074: 'sr-Latn-CS',         108: 'nso',         1132: 'nso-ZA',         50: 'tn',         2098: 'tn-BW',         1074: 'tn-ZA',         4096: 'sn',         4096: 'sn-Latn',         4096: 'sn-Latn-ZW',         89: 'sd',         31833: 'sd-Arab',         2137: 'sd-Arab-PK',         91: 'si',         1115: 'si-LK',         27: 'sk',         1051: 'sk-SK',         36: 'sl',         1060: 'sl-SI',         119: 'so',         1143: 'so-SO',         48: 'st',         1072: 'st-ZA',         10: 'es',         11274: 'es-AR',         8202: 'es-VE',         16394: 'es-BO',         13322: 'es-CL',         9226: 'es-CO',         5130: 'es-CR',         7178: 'es-DO',         12298: 'es-EC',         17418: 'es-SV',         4106: 'es-GT',         18442: 'es-HN',         22538: 'es-419',         2058: 'es-MX',         19466: 'es-NI',         6154: 'es-PA',         15370: 'es-PY',         10250: 'es-PE',         20490: 'es-PR',         1034: 'es-ES_tradnl',         3082: 'es-ES',         21514: 'es-US',         14346: 'es-UY',         4096: 'zgh',         4096: 'zgh-Tfng-MA',         4096: 'zgh-Tfng',         29: 'sv',         2077: 'sv-FI',         1053: 'sv-SE',         90: 'syr',         1114: 'syr-SY',         40: 'tg',         31784: 'tg-Cyrl',         1064: 'tg-Cyrl-TJ',         95: 'tzm',         31839: 'tzm-Latn',         2143: 'tzm-Latn-DZ',         73: 'ta',         1097: 'ta-IN',         2121: 'ta-LK',         68: 'tt',         1092: 'tt-RU',         74: 'te',         1098: 'te-IN',         30: 'th',         1054: 'th-TH',         81: 'bo',         1105: 'bo-CN',         115: 'ti',         2163: 'ti-ER',         1139: 'ti-ET',         49: 'ts',         1073: 'ts-ZA',         31: 'tr',         1055: 'tr-TR',         66: 'tk',         1090: 'tk-TM',         2080: 'ur-IN',         34: 'uk',         1058: 'uk-UA',         46: 'dsb or hsb',         1070: 'hsb-DE',         32: 'ur',         1056: 'ur-PK',         128: 'ug',         1152: 'ug-CN',         30787: 'uz-Cyrl',         2115: 'uz-Cyrl-UZ',         67: 'uz',         31811: 'uz-Latn',         1091: 'uz-Latn-UZ',         2051: 'ca-ES-valencia',         42: 'vi',         1066: 'vi-VN',         82: 'cy',         1106: 'cy-GB',         136: 'wo',         1160: 'wo-SN',         120: 'ii',         1144: 'ii-CN',         106: 'yo',         1130: 'yo-NG',         52: 'xh',         1076: 'xh-ZA',         53: 'zu',         1077: 'zu-ZA'     };
    var currentUserLanguage = SP.PageContextInfo.get_currentLanguage();
    $.each(language, function (lcid, value) {         if (lcid == currentUserLanguage) {             var switchLanguage = value;             $("html").attr('id', 'pageHTML');             document.getElementById("pageHTML").setAttribute('lang', switchLanguage)         }     }); }




Windows 8.1 App – jQuery Version 2.1.0 causing HTML1701: Unable to add dynamic content errors

If you are developing Windows 8.1 Apps, it appears an issue with jQuery version 2.1.0 causes “HTML1701: Unable to add dynamic content…” errors. This occurs even if jQuery code is not in use, but merely the link to jQuery is included in your code. Switching to jQuery 2.0.2 resolved the issue for me. The errors were as follows:

HTML1701: Unable to add dynamic content ”. A script attempted to inject dynamic content, or elements previously modified dynamically, that might be unsafe. For example, using the innerHTML property to add script or malformed HTML will generate this exception. Use the toStaticHTML method to filter dynamic content, or explicitly create elements and attributes with a method such as createElement.  For more information, see http://go.microsoft.com/fwlink/?LinkID=247104.

HTML1701: Unable to add dynamic content ”. A script attempted to inject dynamic content, or elements previously modified dynamically, that might be unsafe. For example, using the innerHTML property to add script or malformed HTML will generate this exception. Use the toStaticHTML method to filter dynamic content, or explicitly create elements and attributes with a method such as createElement.  For more information, see http://go.microsoft.com/fwlink/?LinkID=247104.

I am sure that this issue will be resolved, but in the meantime, I hope this helps others who may come across these error messages.


Using the SharePoint 2013 Trending Tags Web Part Outside of My Sites

Bernado Nguyen-Hoan has found an easy to follow method for using the Trending Tags Web Part outside of My Sites. You can view his post here:


The one challenge I faced was that since I needed to work in SharePoint 2013 Online, and am hesitant about activating the My Site Host feature, I would get errors when someone clicked on a hashtag related to a missing display template.

However, Bernado had an excellent suggestion of copying the  Control_Tagfeed.html display template from a My Site and uploading this to the non-My Site destination I needed to use it in. The display template is found in the Master Page Gallery via the following path:

Site Settings > Web Designer Galleries > Master Pages > Display Templates > System

You then copy the Control_Tagfeed.html file to the Master Page Gallery in your destination Site Collection. Please note that only the HTML file is required, as SharePoint will generate the corresponding JavaScript file for you.

IMPORTANT: Make sure to publish the generated JavaScript file as users with “View” access will not have full functionality while users with “Contribute” can.

Happy tagging!

Sponsored Links