Search

Binary Jam

Simon's blog, SharePoint, Arduino type things.

Category

Javascript

BrowserSync, gulp based script, handling middleware via Corp proxy

Phew that was a long title.  So what’s this about.

I live in a land of corporate proxies with giant .pac scripts, of https services and authenticated proxies.

It …makes….all….this….js….dev… HELL.

I use browser-sync as my local testing sever, its great,  I need it to handle requests to remote apis because of CORS and other security issues, until I can wrap a proxy around the remote system, even then its handy to have the ability to proxy the api calls via a node server (browser sync) for me.

This becomes an absolute bloody nightmare when you have an authenticated corporate proxy server.

None of the JS tools play nice,  there is no such thing as a centralised store for proxy settings, so you have to enter then in the .rc file of every tool, git, npm, bower, and now the custom middleware.  This is where windows got it right and Linux, well sucks.   Oh I wish that I still had ISA servers client transparent proxy.

So the example I have here is a gulp file, that configures browser-sync to run and to call into the middleware extension to handle proxying of api calls to my remote system and for that component to play nice with the corporate proxy.

You need the agent, I tried without it and failed miserably.

gulpfile.js

var gulp = require('gulp');
var browserSync = require('browser-sync').create();
var proxy = require('http-proxy-middleware');
var HttpsProxyAgent = require('https-proxy-agent');

var proxyServer = "http://localhost:8080";   //Cos Fiddler yeh!

var jsonPlaceholderProxy = proxy('/api/', {
    target: 'https://www.binaryjam.com',
    changeOrigin: true,
    logLevel: 'debug',
    secure: true,
    agent:new HttpsProxyAgent(proxyServer)
});

gulp.task('default', function () {
  browserSync.init({
    "port": 8000,
    injectChanges: true,
    "files": ["./src/**/*.{html,htm,css,js,json}"],
    "server": { "baseDir": "./src" },
    "middleware":jsonPlaceholderProxy
  });
});

 

 

 

 

 

 

 

 

 

Adventures in BrowserSync

I’m real new to browsersync and node development. So this has been a pretty steep learning curve, but I thought I’d document something I had to figure out as the documentation and guides on the web are hard to find or just missing.

For those who don’t know and are new to this javascript lark, browsersync is tool that runs under node to create a mini web server, but also it injects javascript into your pages and communicates to the server when the file watcher sees a change to a file.

The effect of this is you can configure it, then run this thing to point at the files in your directory that you are editing, it will fire up a browser and as soon as you save a file it will reload the page.  A real cool feature is called hot reloading, in certain circumstances and configuration it can detect you have changed say an image or css file and it will only change that item in the page, it uses JS to mangle it to the new version and won’t do a full page reload.

I’m using a modified version of browsersync called lite-server, by john papa, just because it was the one I came across first. I’ll be honest I’m not sure what lite-server gives me over browsersync native, it’s just where I started.  That said, you will spend a lot of time reading the browsersync docs not the lite-server page.

The main point of me writing this article was that as well as serving pages and auto reload, browsersync gives me the ability to handle API calls and proxy them to local files (possible another server but I’m not there yet).

In the framework I’m writing, to mimic the new SP framework (early days though) experience but on legacy stuff to deliver a sandbox WSP, the example code makes a call using SPServices library (this could be REST) that call as you may know has the path _vti_bin in it.  So my browsersync config has code in it (the config is javascript) that can intercept this and deliver my content instead.

Below is the bs-config.js file I wrote to achieve this.

The module.exports is the standard bit that configures bs with what files to the watch and how to configure the mini server

The special part is the middleware setting. I have set it so that the 2nd param points to my handleApi function call.  The reason I set the 2nd param (thats the “1:” bit) is that if you clear the 1st parameter then it no longer logs to the console the items its serving, which is handy.

As you can see the handleApiCall function is real simple, it detects the “_vti_bin” in the path and reads a file from a specific place and puts it out in the response stream along with the correct headers for xml.

This could be improved, lots, it could read the request object and parse it to determine what file to send back.

Of course someone has probably already done something like this, but I needed to do something quickly and there is enough to learn.

Saything that I will be looking into proxy-middleware a module for express/browsersync that will likely proxy to a real server not just my local files.

Alternatively https://www.npmjs.com/package/apimock-middleware.

You learn there are so many OS projects out there in npm land so its hard to find the right things.

// jshint node:true
function handleApiCall(req, res, next) {
    
    if (req.url.indexOf('_vti_bin') !== -1) {
        var fs = require("fs");
        fs.readFile("./WebComponents/.container/.mockapi/1.xml",function (err, data) {
            if (err) throw err;
            res.setHeader('Content-Type', 'text/xml');
            res.end(data.toString());
        });
     
    }
    else{
        next();
    }
}

module.exports = {
    'port': 8000,
    'files': [
        './WebComponents/src/**/*.*'
    ],
    'server': {
        'baseDir': './WebComponents/src',
        'middleware': {            2:handleApiCall        }
    }
};

Braindump:Adding CORS support to old SOAP Webservice

This has been a bit of a nightmare,  once you start you will find hundreds of stackexchange articles about this and the problems you will have.

So here are some key things.

Below IE11 ? (maybe 10)  CORS support was provided with the XDR object and this wasn’t automatically used in libraries like jQuery so your jQuery stuff wont work because IE doesnt use the proper XMLHttpRequest objects or what it has is borked.  Till now at least.     So IE11 right!.

There is some simple code you need in your .NET project.

This extract of System.webserver is needed (Dont just paste this you have to insert it into an existing section of your web.config.

This will allow ANYONE to connect. So go read up what each of these attribute do.
What they will do together is all get added to the HTTP headers returned to the server on all items, yes including your aspx pages, now feel free to work out how to restrict that, I had enough by this point and my site only has two things on it both needing this.

  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <!-- CORS Enabled -->
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" />
        <add name="Access-Control-Allow-Headers" value="origin, content-type, accept" />
        <add name="Access-Control-Allow-Credentials" value="true" />
        <add name="Access-Control-Max-Age" value="31536000" />
      </customHeaders>
    </httpProtocol>
</system.webServer>

Next you will need a global.asax  (not a global.aspx.cs like some guides refer to)

The function Application_BeginRequest is one of those that gets called as part of the request lifecycle.
What we are doing here is handling the case when you are doing a non-standard request which for SOAP services will actually be “text/xml;”

Having a non-standard request initiates part of the CORS protocol that does what they call a pre-flight request, to ask the server, “is this allowed or what?”, you are reponding with a A=OK matey.

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.StatusCode = 200;
        HttpContext.Current.Response.End();
    }
}

Thats its.  That’s all you need to do server side to do this.

A matching client side request might look like this

$.ajax({
       url: serviceUrl,
       type: "POST",
       dataType: "xml",
       data: soapEnv,
       crossDomain: true,
       contentType: "text/xml; charset="utf-8"",
})

For me all this started working.  I did all my mappings, and pushed my array into knockout observables and Chrome was working brilliantly.

Then came IE. The pain, the endless searches.

Whilst debugging this I could see my “options” (preflight) request was being made and IE reported no headers returned.  Which was nonsense cos chrome was doing it and working.

I rewrote that C# code over and over with many alternatives.  Chatted to a nodejs bloke who showed me his code, which did exactly the same (well close enough).

That code works.

I saw articles that said that the website your connecting has to be in the Intranet security zone.  Bullshit! If that’s the case how can you connect to yahoo or any other CORS compliant service.

So the one to watch when your developing this stuff.   SELF CERT SSL.

If you have created a self cert and you browse to the service in IE and its got a RED un trusted cert and it will to begin with, this wont work.  The confusing part is the chrome doesnt care, and also IE issues and gets the OPTIONS http request, instead of throwing an error before hand, it shows a 200 status, but it has to issue a request to know its not secure, its why it doesnt show any headers in the network analysis I suspect because at that point it just goes “eeek” and stops.

So export your certificate, dont next next next it,  export it specifically to “trusted root” *  DO THAT AT YOUR OWN RISK, if your not sure dont do it and go buy a proper cert to get this working.

Close your browser and check it worked by navigating to the service endpoint in the browser, if its not red it worked, if it is go do it again, but right.

With all this done you ajax call from IE11 should work with CORS.

If it don’t well good luck :-).

 

Pseudo Synchronous Call Queuing in Angular with promises

Here is example code that batches aync ajax calls into blocks of 5 and waits before calling the next set, without blocking the UI thread.

Continue reading “Pseudo Synchronous Call Queuing in Angular with promises”

SharePoint 2013 App – AngularJs, BootStrap and ngGrid example

I’ve created a SP2013 App including all the code and published it on Codeplex so anyone can take a look and steal the code get ideas.

It has an example of two data fetch techniques (see my earlier blog post for the third external data using the proxy)

using $http to get REST data or $.ajax to get legacy WebService Data.  With the appropriate angular code to handle either, no antipatterns here.

Perhaps I should have used SPServices instead of $.ajax it would have made it easier and I would not have blatantly nicked Marcs getZrows function (thanks Marc 😉  )

https://spappnggrid.codeplex.com/

Capture

Last Update:14/10/2014
Organised into folders and separate files for controllers and services. Changed Service to Factory.
(Service code left in project for example purposes)

 

 

List of JS Libraries I’m using / looking into

This is more of a note to myself so that I can remember the JavaScript libraries I’m interested in and what they do and maybe a related article.  These are mainly in dealing with SharePoint but could be anything really.  Not everything is compatible with everything else remember 🙂

 

KnockoutJs – Data binding library, works with jQuery, great for a true single page app, IE no routing just data binding.  Yes I know SPA’s pages are called views.

AngularJS – Proper SPA framework, there’s Durandal but I’?m not going there even though I love knockout.

BreezeJs

    – Linq Like queries, does need server side integration, not for local objects

Bootstrap – For that nice CSS layout grids and things.

Bootstrap UI – Directives for Angular using bootstrap

Angular Maps – Google maps directives for angular, something I’ve used already.

 

LinqJs – Linq for JavaScript, will work on JS objects, doesn’t do fetch for you

Js Loaders – http://requirejs.org/  and  http://labjs.com/

jQuery – Well how could I not mention it.

jQuery form validators

Sliders – http://slippry.com/ , http://bxslider.com/, http://workshop.rs/projects/coin-slider/

fontawesome – No idea, well something to do with a shed load of CSS icons, vectors (no IE7)

Charts – jqPlot, http://www.flotcharts.org/, hicharts

Spinner – svg/vml Spinner, easier than a gif ?

 

Stuff to investigate

 

Not a library but a list of handy SP2013 dev tools

Zimmergrens SP2013 Tools Page

Angular Google Maps Example

I’m trying to get my head around angular and using it for writing SharePoint Apps, but one of the first things I wanted to write used google maps.

Luckily (or not depending on how much pain you want to know this caused me) there is a directive library for google maps.

After far too many save and refresh and crash cycles I have a simple example working that has markers and info windows.

Here it is

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>angular-google-maps example</title>
<style>
        .angular-google-map-container {
            height: 800px;
        }
    </style>
<!-- Google Maps API v3 -->
<script src="http://maps.googleapis.com/maps/api/js?sensor=false&amp;language=en"></script>
<!--  v1.0.8 -->
<script src="angular.min.js"></script>
<!-- http://underscorejs.org/ -->
<script src="underscore-1.6.0.min.js"></script>
<!-- http://angular-google-maps.org -->
<script src="angular-google-maps.min.js"></script>
</head>
<body>
     <div ng-app="BinaryJamApp">
         <div ng-controller="MappingController">
 		<google-map  center="map.center" zoom="map.zoom" draggable="true" events="map.events"  options="map.options" pan="true"  control="map.control">
			<markers models="sites" coords="'self'" click="'onClicked'">
 				<windows show="'showWindow'" closeClick="'closeClick'" ng-cloak>
 					<p ng-non-bindable style="width:200px">{{ options.title }}</p>
 					<p ng-non-bindable>{{ latitude | number:4 }}, {{ longitude | number:4 }}!</p>
				</windows>
 			</markers>
 		</google-map>
         </div>
     </div>
     <script>
        var BinaryJamApp = angular.module('BinaryJamApp', ['google-maps']);

        function MappingController($scope) {
			$scope.sites=[];

			$scope.map = {
				control: {},
				options: {
					streetViewControl: false,
					panControl: false,
					maxZoom: 20,
					minZoom: 3
				},
				center: {
					latitude: 52,
					longitude: 0
				},
				zoom: 6
			};

			var onMarkerClicked = function (marker) {
				marker.showWindow = true;
				$scope.$apply();
			}; 

			$scope.sites.push({latitude:52, longitude:0, options: { title: "Southerners" } });
			$scope.sites.push({latitude:52.5, longitude:1, options: { title: "Turkeys" } });

			_.each($scope.sites, function (site) {
				site.closeClick = function () {
					site.showWindow = false;
					$scope.$apply();
				};
				site.onClicked = function () {
					onMarkerClicked(site);
				};
			});

        }

    </script>
  </body>
 </html>

SharePoint 2010/13 Getting the Default Disp Page in JSOM

Being pretty new to JSOM, thought I might write this down so I don?t forget again.

JSOM is just quite a bit different to REST or SPServices or just ferreting around the old server API, so it’s going to take some time.  Give me REST any day, but today I find myself altering some one else’s code.

I needed to find the default display page Url

Well it’s pretty simple, but web examples are gathering all list information the code I had was getting a specific list, not sure that they are still not getting all lists, but hey.

Adding the paramter “Include(DefaultDisplayFormUrl)” into the getByTitle function, instructs CSM that you want this bit of info.

 

   

   <script>


 targetList = clientContext.get_web().get_lists().getByTitle("Glossary", "Include(DefaultDisplayFormUrl)");  


</script> 

 

But you can’t access it immediately.

No you have to wait until after the executeQueryAsync only then can you call the function on the targetList variable, so watch those scopes,

   <script>

 
  targetList = clientContext.get_web().get_lists().getByTitle("Glossary", "Include(DefaultDisplayFormUrl)");  
 
  
  clientContext.executeQueryAsync(
      Function.createDelegate(this, function() { alert( targetList.get_defaultDisplayFormUrl();) } ),
      Function.createDelegate(this, function() {alert("failed")})
  );	

</script> 
Technorati Tags: ,,

Using jQuery Queue with SPServices

One of the problems I came across the other day is I had several hundred items in a list to process.  To make life easy I use javascript on a web part page to make an app to process the items I wanted to do. 

However when its hundreds, do them all at once and you’re in trouble.  You block the UI thread, you cant update any status values, I dare not think what would happen if you called a couple of hundred async ajax queries all at once, it might just handle them – you can try it if you want 😉

To get round this I thought I’d try to use jQuery queues.  So in this example I have a custom list which I get data from, I’m using promises to get the data but there was no need, I just used some code from the last example.  Once I have the data I inject it onto the screen an lose the original data array (now this is the point where I should use knockout and let the screen adjust to the observed data, but this is a demo).  Then on a click event, a big process this now button, I iterate thru each item on the page, gets its details and add a function to the queue that calls another function (just for being tidy I could embed) which makes a call to SPServices async update, phew.

Then I tell the queue to start executing the functions in it, one at a time.  At the end of each async success, it calls the next function, you might spot the mistake here, what if it doesn’t succeed (well I forgot to code it, but you need to do something with the item and the queue when you do it).

Hint: When calling functions and sub functions, make sure you “var” every variable, I forgot and it only updated the last item.

Technorati Tags: ,,

Here’s the code

 

 <script src="js/jquery.SPServices-0.7.1a.min.js"></script>  <script src="js/underscore.min.js"></script>   <div id="mainApp" > 	<div id="appStatus">Initialising</div>	<div id="appButton" style="cursor:hand;display:none">Click Me</div> 	<div id="appBody"></div>  </div>        <script>


var binaryJamQueueTest = function ($) {
   
   	//Private Members
  	var testListArray;

	function main() {
		
		$("#appStatus").text("Loading");

		//Remember that $.when is an async function also, so dont put anything after this code
		//unless you want it running immediately, in which case stick it here first.
		$.when(asyncGetTestList())
		.fail(function() {
			loadFailure();
		})
		.done(function(){
			dataReady();
		});
		
  	}
  	
  	function loadFailure() {
  		//Oh dear
	  	$("#appStatus").text("Failed to Load data");
  	}
  	
  	function dataReady() {
  		$("#appStatus").text("Processing Data");
  		
  		//Earlier versions did not queue so in cases where you will thread block
  		//use something like this to give the DOM time to update
  		setTimeout(function() {
	  		processList();
	  	}, 10);
  		
  	}
  	
  	
  	function asyncGetTestList() {
  	
  		var dfd = $.Deferred();
  		
		$().SPServices({          
			operation: "GetListItems",          
			async: true,          
			listName: "TestList", 
			CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='name' /><FieldRef Name='valueField' /></ViewFields>",

			completefunc: function(data, status) { 
				if (status== "success") {
					testListArray=$(data.responseXML).SPFilterNode("z:row").map(function() 
	                { 
							return {
								id: $(this).attr('ows_ID'), 
		                        title: $(this).attr('ows_Title') , 
		                        name: $(this).attr('ows_name') ,
		                        value: parseInt($(this).attr('ows_valueField')) 
		                    }; 
	                 }); 
					dfd.resolve("");				
				}
				else
				{
					dfd.reject();
				}
			} 
		}); 
		
		return dfd.promise();
  	}
  	
  	
  	function updateListItem(id, title, value, $item, next)
  	{
		//Notice here, if I was databinding I would only have to update the value not the html item
	  	$().SPServices({
			operation: "UpdateListItems",
			async: true,
			ID: id,
			listName: "TestList",
			valuepairs: [ ["valueField", value]],
			completefunc: function(xData, Status) {
				$item.text(title + " " + value);
				$item.attr('value', value);
				next();
			}
		});
	
  	}
  	
  	function processList()
  	{
		var $taskQueue=$({});
		
  		var htmlAdd="";
		$.each(testListArray, function(locIndex, testListRow) {
			
				htmlAdd+="<li id='" + testListRow.id + 
								"' title='" + testListRow.title + 
								"' name='" + testListRow.name + 
								"' value='" + testListRow.value + 
						  "'>" + testListRow.title + " " +
						 testListRow.value + 
						 "</li>";
								
				s="";
			
		});
		
		//Clear the original list Im going to use stuff onscreen, I know its wrong and not MVC
		//But Hey you do it the right way with a data binding library instead
		testListArray={};
  		
  		html=$("<ul id='itemsToProcess'>" + htmlAdd+ "</ul>");
		$("#appBody").html(html);
  		$("#appStatus").text("Ready");
  		$("#appButton").show();



  		$("#appButton").click(function() {
  		
			$.each($("#itemsToProcess").children(), function() {
				var $currentLi=$(this);
				$taskQueue.queue('tasks', function(next) {
	  				var id =$currentLi.attr('id');
	  				var title =$currentLi.attr('title');
	  				var value=parseInt($currentLi.attr('value'));
	  				updateListItem(id, title, value+1, $currentLi, next );
	  				
	  				
				});
			});

			$taskQueue.dequeue('tasks');
  		});
  				
  	}


	//Public Members
  	return {
   		init : main
  	}

  
}(jQuery); //binaryJamQueueTest Module


jQuery(function () {

    binaryJamQueueTest.init();
});


</script>  

Create a free website or blog at WordPress.com.

Up ↑