<commit_before>// stackptr-mapview.js
// this is for stuff specific to stackptr.com, not external maps

//window.stackptr.resize(fixheight);

var app = angular.module("StackPtr", ['leaflet-directive', 'angularMoment', 'ngAnimate', 'ngSanitize', 'mgcrea.ngStrap', 'vxWamp']).config(function($interpolateProvider){
	$interpolateProvider.startSymbol('[[').endSymbol(']]');
});

app.config(function ($wampProvider) {
     $wampProvider.init({
        url: 'wss://stackptr.com/ws',
        realm: 'stackptr',
        authmethods: ["ticket"],
        //Any other AutobahnJS options
     });
 });

app.run(function($http) {
	$http.defaults.headers.post['X-CSRFToken'] = $('meta[name=csrf-token]').attr('content');
	$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';

});

app.controller("StackPtrMap", [ '$scope', '$http', '$interval', 'leafletData', '$wamp', function($scope, $http, $interval, leafletData, $wamp ) {
	angular.extend($scope, {
		defaults: {
			maxZoom: 18,
			minZoom: 1,
			doubleClickZoom: true,
			scrollWheelZoom: true,
			attributionControl: true,
			tileLayer: 'https://tile{s}.stackcdn.com/' + (L.Browser.retina ? 'osm_tiles_2x' : 'osm_tiles') +'/{z}/{x}/{y}.png',
			//tileLayer: 'https://otile{s}-s.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png',
			tileLayerOptions: {
				attribution: '© OpenStreetMap contributors',
				maxZoom: 18,
				subdomains: '123456',
			},
		},
		center: {
			lat: -24,
			lng: 138,
			zoom: 5,
		},
		controls: {
			draw: {},
			edit: {featureGroup: L.featureGroup()},
		},
	});

	$scope.markers = {};
	$scope.userList = {};
	$scope.userPending = {};
	$scope.userReqs = {};
	$scope.grouplist = {};
	$scope.groupdata = {};
	$scope.userListEmpty = false;
	$scope.pendingListEmpty = false;
	$scope.reqsListEmpty = false;

	$scope.processItem = function(item) {
		console.log(item);
			if (item.type == 'user') {
				for (user in item.data) {
					if (item.data[user] == null) {
						delete $scope.userList[user];
						delete $scope.markers[user];
					} else {
						$scope.userList[user] = item.data[user];
						$scope.updateMarker(item.data[user]);
					}
				}
				$scope.userListEmpty = (Object.keys($scope.userList).length) == 0;
			} else if (item.type == 'user-me') {
				$scope.userMe = item.data;
				$scope.updateMarker(item.data);
			} else if (item.type == 'user-pending') {
				for (user in item.data) {
					if (item.data[user] == null) {
						delete $scope.userPending[user];
					} else {
						$scope.userPending[user] = item.data[user];
					}
				}
				$scope.pendingListEmpty = (Object.keys($scope.userPending).length) == 0;
			} else if (item.type == 'user-request') {
				for (user in item.data) {
					if (item.data[user] == null) {
						delete $scope.userReqs[user];
					} else {
						$scope.userReqs[user] = item.data[user];
					}
				}
				$scope.reqsListEmpty = (Object.keys($scope.userReqs).length) == 0;
			} else if (item.type == 'grouplist') {
				for (group in item.data) {
					$scope.grouplist[group] = item.data[group];
				}
			} else if (item.type == 'groupdata') {
				for (groupitem in item.data) {
					$scope.groupdata[groupitem] = item.data[groupitem];
				}
			} else {
				console.log(item);
			}
	}

	$scope.processData = function(data, status, headers, config) {
		console.log(data);
		for (msg in data) {
			var item = data[msg];
			$scope.processItem(item);
		}
	};

	$scope.counter = 0;
	$scope.status = "Connecting to server...";

	//$scope.update = function() {
	//	if (--$scope.counter < 0) {
	//		$scope.counter = 5;
	//
	//		var resp = $http.get("/users");
	//		resp.success($scope.processData);
	//
	//		var resp = $http.get("/grouplist");
	//		resp.success($scope.processData);
	//
	//		var resp = $http.post('/groupdata', $.param({group: 1}));
	//		resp.success($scope.processData);
	//
	//	};
	//};

	//$scope.update();
	//$interval($scope.update, 1000);

	$scope.clickMarker = function(user) {
		$scope.center.lat = user.loc[0];
		$scope.center.lng = user.loc[1];
		$scope.center.zoom = 16;
		$scope.markers[user.id].focus = true;
	}

	$scope.updateMarker = function(userObj) {
		//var userObj = $scope.userList[user];

		if ($scope.markers[userObj.id] == null) {
			$scope.markers[userObj.id] = {
				icon: {
					iconUrl: userObj.icon,
					iconSize: [32,32],
					iconAnchor: [16,16],
				},
				message: "Delete user",
				focus: false,
			};
		}
		$scope.markers[userObj.id].lat = userObj.loc[0];
		$scope.markers[userObj.id].lng = userObj.loc[1];
	}

	//$scope.$watchCollection('userList', function(added,removed) {
	//	var markerList = {};
	//	for (user in added) {
	//		console.log("added: " + user)
	//		var userObj = $scope.userList[user];
	//		var marker = {
	//			lat: userObj.loc[0],
	//			lng: userObj.loc[1],
	//			icon: {
	//				iconUrl: userObj.icon,
	//				iconSize: [32,32],
	//				iconAnchor: [16,16],
	//			},
	//		};
	//		markerList[$scope.userList[user].username] = marker;
	//	}
	//	angular.extend($scope, {markers: markerList});
	//});

	$scope.layers = {}
	$scope.$watchCollection('groupdata', function(added, removed) {
		$scope.features = [];
		for (itemid in added) {
			var item = $scope.groupdata[itemid];
			$scope.features.push(item.json);
		}
		//console.log($scope.features);

		angular.extend($scope, {
			geojson: {data: {"type":"FeatureCollection","features":$scope.features}},
		});
	});

	$scope.$on("leafletDirectiveMap.geojsonClick", function(ev, featureSelected, leafletEvent) {
		alert(featureSelected.id);
	});

	leafletData.getMap().then(function(map) {
              var drawnItems = $scope.controls.edit.featureGroup;
              map.addLayer(drawnItems);
              map.on('draw:created', function (e) {
                var layer = e.layer;
                //drawnItems.addLayer(layer);
                //console.log(JSON.stringify(layer.toGeoJSON()));
				var resp = $http.post('/addfeature', $.param({
					group: '1',
					geojson: JSON.stringify(layer.toGeoJSON()),
				}));
				resp.success($scope.processData);
				//resp.success(function(d,s,h,c) {console.log(d)});
              });
           });

	$scope.activePanel = -1;

	$scope.addUser = function($event) {
		var formdata = $($event.target.form).serialize();
		var resp = $http.post('/adduser', formdata);
		//alert(resp);
		resp.success($scope.processData);
	};

	$scope.delUser = function(uid) {
			//var resp = $http.get("/deluser");
			//resp.success($scope.processData);

			var resp = $http.post('/deluser', $.param({uid: uid}));
			resp.success($scope.processData);

			return 1;
	}

	$scope.acceptUser = function(uid) {
			//var resp = $http.get("/deluser");
			//resp.success($scope.processData);

			var resp = $http.post('/acceptuser', $.param({uid: uid}));
			resp.success($scope.processData);

			return 1;
	}

	$scope.renameGroupItem = function($event) {
		var formdata = $($event.target.form).serialize();
		var resp = $http.post('/renamefeature', formdata);
		resp.success($scope.processData);
	};

	$scope.gotoItem = function(item) {
		var items = $scope.geojson.data.features;
		for (i in items) {
			if (items[i].id == item) {
				var bounds = L.bounds(items[i].geometry.coordinates);
			}
		}

	}

	var resp = $http.post('/ws_uid', "");
	resp.success(function(rdata, status, headers, config) {
		console.log(rdata);
		$wamp.connection._options.authid = rdata;
		$wamp.open();
	});

	$scope.$on("$wamp.onchallenge", function (event, data) {
		console.log(data);
    if (data.method === "ticket"){
        var resp = $http.post('/ws_token', "");
		resp.success(function(rdata, status, headers, config) {
			console.log(rdata);
			return data.promise.resolve(rdata);
		});

     }

	});

	$scope.$on("$wamp.open", function (event, session) {
        $scope.status = "Connected";

        //$wamp.call('com.stackptr.api.idlist').then(function(res) {
    	//	console.log(res);
    	//	for (i in res) {
		//		$wamp.subscribe('com.stackptr.user.' + res[i], $scope.processWS);
		//	}
    	//});

    	$wamp.subscribe('com.stackptr.user', $scope.processWS);

        $wamp.call('com.stackptr.api.userList').then($scope.processData);
        $wamp.call('com.stackptr.api.groupList').then($scope.processData);

    });

    $scope.$on("$wamp.close", function (event, data) {
    	$scope.status = "Disconnected: " + data.reason;
        $scope.reason = data.reason;
        $scope.details = data.details;
    });

    $scope.processWS = function(type, data) {
		$scope.processItem({type: type[0], data: data.msg});
   	};

}]);

app.filter('updateRange', function () {
  return function (items, agemin, agemax) {
  	var curTime = Math.round(new Date().getTime()/1000);
    var filtered = [];
    for (id in items) {
    	var item = items[id]
		var updateTime = curTime - item.lastupd;
		// fixme: client/server time mismatch
		if (updateTime < 0) {
			updateTime = 0;
		}
      if ((updateTime >= agemin) && ((updateTime < agemax) || (agemax == -1))) {
        filtered.push(item);
      }
    }
    return filtered;
  };
});

$(document).ready(function() {
	//map = L.map('map-canvas').setView([-34.929, 138.601], 13);
	//window.stackptr = new StackPtr("/", undefined, undefined);
	//stackptr.updateFollowing();

	//window.stackptr.bootstrap = true;
	$("#gpsmenu").draggable();
	$("#usermenu").draggable();
	$("#groupmenu").draggable();

	//$("#upload_loc").click(uploadLocation);
	//$("#goto_loc").click(gotoMyLocation);
	//$("#autorefresh_loc").click(toggleAutoRefresh);

	// //$("#selectgroup").change(stackptr.changegroup);

	//stackptr.setupDraw();

	//$("#refresh_loc").click(stackptr.updateFollowing);

	//$("#adduser").click(function(e) {
	//	e.preventDefault();
	//	$.post('/adduser', $('#adduserform').serialize(),
	//		function(data) {
	//			$("#addstatus").html("Server returned: " + data);
	//			stackptr.refreshLocation();
	//	});
	//});

	//stackptr.setupAutoRefresh();
});

togglePane  = function (pane) {
	$(pane).toggle();
}

function delUserClick(item,uid) {
	var $scope = angular.element($('body')).scope();
	$scope.delUser(uid);
}

function acceptUserClick(item,uid) {
	var $scope = angular.element($('body')).scope();
	$scope.acceptUser(uid);
}<commit_msg>hide groups window<commit_after>// stackptr-mapview.js
// this is for stuff specific to stackptr.com, not external maps

//window.stackptr.resize(fixheight);

var app = angular.module("StackPtr", ['leaflet-directive', 'angularMoment', 'ngAnimate', 'ngSanitize', 'mgcrea.ngStrap', 'vxWamp']).config(function($interpolateProvider){
	$interpolateProvider.startSymbol('[[').endSymbol(']]');
});

app.config(function ($wampProvider) {
     $wampProvider.init({
        url: 'wss://stackptr.com/ws',
        realm: 'stackptr',
        authmethods: ["ticket"],
        //Any other AutobahnJS options
     });
 });

app.run(function($http) {
	$http.defaults.headers.post['X-CSRFToken'] = $('meta[name=csrf-token]').attr('content');
	$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';

});

app.controller("StackPtrMap", [ '$scope', '$http', '$interval', 'leafletData', '$wamp', function($scope, $http, $interval, leafletData, $wamp ) {
	angular.extend($scope, {
		defaults: {
			maxZoom: 18,
			minZoom: 1,
			doubleClickZoom: true,
			scrollWheelZoom: true,
			attributionControl: true,
			tileLayer: 'https://tile{s}.stackcdn.com/' + (L.Browser.retina ? 'osm_tiles_2x' : 'osm_tiles') +'/{z}/{x}/{y}.png',
			//tileLayer: 'https://otile{s}-s.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.png',
			tileLayerOptions: {
				attribution: '© OpenStreetMap contributors',
				maxZoom: 18,
				subdomains: '123456',
			},
		},
		center: {
			lat: -24,
			lng: 138,
			zoom: 5,
		},
		controls: {
			draw: {},
			edit: {featureGroup: L.featureGroup()},
		},
	});

	$scope.markers = {};
	$scope.userList = {};
	$scope.userPending = {};
	$scope.userReqs = {};
	$scope.grouplist = {};
	$scope.groupdata = {};
	$scope.userListEmpty = false;
	$scope.pendingListEmpty = false;
	$scope.reqsListEmpty = false;

	$scope.processItem = function(item) {
		console.log(item);
			if (item.type == 'user') {
				for (user in item.data) {
					if (item.data[user] == null) {
						delete $scope.userList[user];
						delete $scope.markers[user];
					} else {
						$scope.userList[user] = item.data[user];
						$scope.updateMarker(item.data[user]);
					}
				}
				$scope.userListEmpty = (Object.keys($scope.userList).length) == 0;
			} else if (item.type == 'user-me') {
				$scope.userMe = item.data;
				$scope.updateMarker(item.data);
			} else if (item.type == 'user-pending') {
				for (user in item.data) {
					if (item.data[user] == null) {
						delete $scope.userPending[user];
					} else {
						$scope.userPending[user] = item.data[user];
					}
				}
				$scope.pendingListEmpty = (Object.keys($scope.userPending).length) == 0;
			} else if (item.type == 'user-request') {
				for (user in item.data) {
					if (item.data[user] == null) {
						delete $scope.userReqs[user];
					} else {
						$scope.userReqs[user] = item.data[user];
					}
				}
				$scope.reqsListEmpty = (Object.keys($scope.userReqs).length) == 0;
			} else if (item.type == 'grouplist') {
				for (group in item.data) {
					$scope.grouplist[group] = item.data[group];
				}
			} else if (item.type == 'groupdata') {
				for (groupitem in item.data) {
					$scope.groupdata[groupitem] = item.data[groupitem];
				}
			} else {
				console.log(item);
			}
	}

	$scope.processData = function(data, status, headers, config) {
		console.log(data);
		for (msg in data) {
			var item = data[msg];
			$scope.processItem(item);
		}
	};

	$scope.counter = 0;
	$scope.status = "Connecting to server...";

	//$scope.update = function() {
	//	if (--$scope.counter < 0) {
	//		$scope.counter = 5;
	//
	//		var resp = $http.get("/users");
	//		resp.success($scope.processData);
	//
	//		var resp = $http.get("/grouplist");
	//		resp.success($scope.processData);
	//
	//		var resp = $http.post('/groupdata', $.param({group: 1}));
	//		resp.success($scope.processData);
	//
	//	};
	//};

	//$scope.update();
	//$interval($scope.update, 1000);

	$scope.clickMarker = function(user) {
		$scope.center.lat = user.loc[0];
		$scope.center.lng = user.loc[1];
		$scope.center.zoom = 16;
		$scope.markers[user.id].focus = true;
	}

	$scope.updateMarker = function(userObj) {
		//var userObj = $scope.userList[user];

		if ($scope.markers[userObj.id] == null) {
			$scope.markers[userObj.id] = {
				icon: {
					iconUrl: userObj.icon,
					iconSize: [32,32],
					iconAnchor: [16,16],
				},
				message: "Delete user",
				focus: false,
			};
		}
		$scope.markers[userObj.id].lat = userObj.loc[0];
		$scope.markers[userObj.id].lng = userObj.loc[1];
	}

	//$scope.$watchCollection('userList', function(added,removed) {
	//	var markerList = {};
	//	for (user in added) {
	//		console.log("added: " + user)
	//		var userObj = $scope.userList[user];
	//		var marker = {
	//			lat: userObj.loc[0],
	//			lng: userObj.loc[1],
	//			icon: {
	//				iconUrl: userObj.icon,
	//				iconSize: [32,32],
	//				iconAnchor: [16,16],
	//			},
	//		};
	//		markerList[$scope.userList[user].username] = marker;
	//	}
	//	angular.extend($scope, {markers: markerList});
	//});

	$scope.layers = {}
	$scope.$watchCollection('groupdata', function(added, removed) {
		$scope.features = [];
		for (itemid in added) {
			var item = $scope.groupdata[itemid];
			$scope.features.push(item.json);
		}
		//console.log($scope.features);

		angular.extend($scope, {
			geojson: {data: {"type":"FeatureCollection","features":$scope.features}},
		});
	});

	$scope.$on("leafletDirectiveMap.geojsonClick", function(ev, featureSelected, leafletEvent) {
		alert(featureSelected.id);
	});

	leafletData.getMap().then(function(map) {
              var drawnItems = $scope.controls.edit.featureGroup;
              map.addLayer(drawnItems);
              map.on('draw:created', function (e) {
                var layer = e.layer;
                //drawnItems.addLayer(layer);
                //console.log(JSON.stringify(layer.toGeoJSON()));
				var resp = $http.post('/addfeature', $.param({
					group: '1',
					geojson: JSON.stringify(layer.toGeoJSON()),
				}));
				resp.success($scope.processData);
				//resp.success(function(d,s,h,c) {console.log(d)});
              });
           });

	$scope.activePanel = -1;

	$scope.addUser = function($event) {
		var formdata = $($event.target.form).serialize();
		var resp = $http.post('/adduser', formdata);
		//alert(resp);
		resp.success($scope.processData);
	};

	$scope.delUser = function(uid) {
			//var resp = $http.get("/deluser");
			//resp.success($scope.processData);

			var resp = $http.post('/deluser', $.param({uid: uid}));
			resp.success($scope.processData);

			return 1;
	}

	$scope.acceptUser = function(uid) {
			//var resp = $http.get("/deluser");
			//resp.success($scope.processData);

			var resp = $http.post('/acceptuser', $.param({uid: uid}));
			resp.success($scope.processData);

			return 1;
	}

	$scope.renameGroupItem = function($event) {
		var formdata = $($event.target.form).serialize();
		var resp = $http.post('/renamefeature', formdata);
		resp.success($scope.processData);
	};

	$scope.gotoItem = function(item) {
		var items = $scope.geojson.data.features;
		for (i in items) {
			if (items[i].id == item) {
				var bounds = L.bounds(items[i].geometry.coordinates);
			}
		}

	}

	var resp = $http.post('/ws_uid', "");
	resp.success(function(rdata, status, headers, config) {
		console.log(rdata);
		$wamp.connection._options.authid = rdata;
		$wamp.open();
	});

	$scope.$on("$wamp.onchallenge", function (event, data) {
		console.log(data);
    if (data.method === "ticket"){
        var resp = $http.post('/ws_token', "");
		resp.success(function(rdata, status, headers, config) {
			console.log(rdata);
			return data.promise.resolve(rdata);
		});

     }

	});

	$scope.$on("$wamp.open", function (event, session) {
        $scope.status = "Connected";

        //$wamp.call('com.stackptr.api.idlist').then(function(res) {
    	//	console.log(res);
    	//	for (i in res) {
		//		$wamp.subscribe('com.stackptr.user.' + res[i], $scope.processWS);
		//	}
    	//});

    	$wamp.subscribe('com.stackptr.user', $scope.processWS);

        $wamp.call('com.stackptr.api.userList').then($scope.processData);
        $wamp.call('com.stackptr.api.groupList').then($scope.processData);

    });

    $scope.$on("$wamp.close", function (event, data) {
    	$scope.status = "Disconnected: " + data.reason;
        $scope.reason = data.reason;
        $scope.details = data.details;
    });

    $scope.processWS = function(type, data) {
		$scope.processItem({type: type[0], data: data.msg});
   	};

}]);

app.filter('updateRange', function () {
  return function (items, agemin, agemax) {
  	var curTime = Math.round(new Date().getTime()/1000);
    var filtered = [];
    for (id in items) {
    	var item = items[id]
		var updateTime = curTime - item.lastupd;
		// fixme: client/server time mismatch
		if (updateTime < 0) {
			updateTime = 0;
		}
      if ((updateTime >= agemin) && ((updateTime < agemax) || (agemax == -1))) {
        filtered.push(item);
      }
    }
    return filtered;
  };
});

$(document).ready(function() {
	//map = L.map('map-canvas').setView([-34.929, 138.601], 13);
	//window.stackptr = new StackPtr("/", undefined, undefined);
	//stackptr.updateFollowing();

	//window.stackptr.bootstrap = true;
	$("#gpsmenu").draggable();
	$("#usermenu").draggable();
	$("#groupmenu").draggable();

	//$("#upload_loc").click(uploadLocation);
	//$("#goto_loc").click(gotoMyLocation);
	//$("#autorefresh_loc").click(toggleAutoRefresh);

	// //$("#selectgroup").change(stackptr.changegroup);

	//stackptr.setupDraw();

	//$("#refresh_loc").click(stackptr.updateFollowing);

	//$("#adduser").click(function(e) {
	//	e.preventDefault();
	//	$.post('/adduser', $('#adduserform').serialize(),
	//		function(data) {
	//			$("#addstatus").html("Server returned: " + data);
	//			stackptr.refreshLocation();
	//	});
	//});

	//stackptr.setupAutoRefresh();
});

togglePane  = function (pane) {
	$(pane).toggle();
}

togglePane("#groupmenu");

function delUserClick(item,uid) {
	var $scope = angular.element($('body')).scope();
	$scope.delUser(uid);
}

function acceptUserClick(item,uid) {
	var $scope = angular.element($('body')).scope();
	$scope.acceptUser(uid);
}<|endoftext|>


<commit_before>'use strict';
/*globals require,define,describe,it, Jskeleton, before */
/* jshint unused: false */
describe('In view-controller ', function() {
    var sandbox,
        stubNewFactory,
        ViewController,
        viewController,
        viewControllerOptions,
        createViewController,
        mainRegion;

    before(function() {
        sandbox = sinon.sandbox.create();

        stubNewFactory = sandbox.stub(Jskeleton.factory, 'new');

        ViewController = Jskeleton.ViewController;

        createViewController = function(options) {
            return new ViewController(options);
        };

        mainRegion = new Backbone.Marionette.Region({
            el: 'body'
        });

        viewControllerOptions = {
            app: {},
            channel: {},
            region: {}
        };
    });

    it('it exists and extends an object', function() {
        expect(ViewController).to.be.a('function');
        expect(ViewController.prototype).to.be.an('object');
    });

    it('it has all namespace properties', function() {
        expect(ViewController.prototype).to.include.keys(
            'constructor',
            '_ensureOptions',
            'mixinTemplateHelpers',
            'addComponent',
            'destroy',
            '_destroyComponents',
            '_delegateComponentEvent',
            '_undelegateComponentEvent',
            'unbindComponents',
            'bindComponents',
            'render'
        );
    });

    it('we can create a new view-controller object', function() {
        expect(createViewController.bind(this, viewControllerOptions)).to.not.throw(Error);
        expect(createViewController(viewControllerOptions)).to.be.an('object');
    });

    it('throws errors if we try to create a new view-controller with any option missing', function() {
        expect(createViewController).to.throw(Error);

        expect(createViewController.bind(this, {
            app: {},
            channel: {}
        })).to.throw(Error);

        expect(createViewController.bind(this, {
            app: {},
            region: {}
        })).to.throw(Error);

        expect(createViewController.bind(this, {
            region: {},
            channel: {}
        })).to.throw(Error);

    });

    describe('When we have a view-controller object', function() {
        var ViewComponent,
            viewComponent,
            OtherViewComponent,
            otherViewComponent,
            viewController,
            viewComponentSpyEvent,
            otherViewComponentSpyEvent,
            viewControllerSpyEvent;

        beforeEach(function() {

            ViewComponent = Jskeleton.ItemView.extend({
                template: ' Test Title ',
                events: {
                    'click #view-action': 'onActionClicked',
                },
                onActionClicked: function(event) {
                    this.trigger('buy', event);
                }
            });

            OtherViewComponent = Jskeleton.ItemView.extend({
                template: ' Other Test Title ',
                events: {
                    'keypress #other-view-action': 'onActionKeypress',
                },
                onActionKeypress: function(event) {
                    this.trigger('sell', event);
                }
            });

            ViewController = Jskeleton.ViewController.extend({
                events: {
                    'buy @component.viewComponent': 'onLink',
                    'sell @component.otherViewComponent': 'onLink'
                },
                template: 'viewComponent: {{@component name="viewComponent"}}' +
                    'otherViewComponent: {{@component name="otherViewComponent"}}',
                onLink: function(event) {},
            });

            viewComponentSpyEvent = sinon.spy(ViewComponent.prototype,
                'onActionClicked');

            viewComponent = new ViewComponent();

            stubNewFactory.withArgs('viewComponent').returns(viewComponent);

            otherViewComponentSpyEvent = sinon.spy(OtherViewComponent.prototype,
                'onActionKeypress');

            otherViewComponent = new OtherViewComponent();

            stubNewFactory.withArgs('otherViewComponent').returns(otherViewComponent);

            viewController = createViewController(viewControllerOptions);

            viewControllerSpyEvent = sinon.spy(viewController, 'onLink');

        });

        it('we can add components', function() {
            expect(viewController.components).to.be.an('object');

            viewController.addComponent('ViewComponent', viewComponent);
            expect(Object.keys(viewController.components)).to.have.length.above(0);

            viewController.addComponent('OtherViewComponent', otherViewComponent);
            expect(Object.keys(viewController.components)).to.have.length.above(1);
        });

        describe('When we render it in a region', function() {
            var componentListeners;

            beforeEach(function() {
                mainRegion.show(viewController);
            });

            it('it is rendered', function() {
                expect(viewController.isRendered).to.be.true;
            });

            it('all its components are rendered', function() {
                expect(viewComponent.isRendered).to.be.true;
                expect(otherViewComponent.isRendered).to.be.true;
            });

            it('has all component events attached to it', function() {
                componentListeners = [];

                _.each(viewController._listeningTo, function(listener) {
                    componentListeners.push(listener._listenId);
                });

                _.each(viewController.components, function(classComponents) {
                    _.each(classComponents, function(component) {
                        expect(_.contains(componentListeners, component._listenId))
                            .to.be.true;
                    });
                });
            });

            it('events run properly', function() {
                $('#view-action').click();
                $('#other-view-action').keypress();

                expect(viewComponentSpyEvent.calledOnce).to.be.equal(true);
                expect(otherViewComponentSpyEvent.calledOnce).to.be.equal(true);
                expect(viewControllerSpyEvent.calledTwice).to.be.equal(true);
            });

            it('refreshing the components they are resetted', function() {
                var AnotherViewComponent = Jskeleton.ItemView.extend({
                    template: ' another Test Title ',
                });

                var anotherViewComponent = new AnotherViewComponent();

                stubNewFactory.withArgs('anotherViewComponent').returns(anotherViewComponent);

                viewController.template = 'refresh viewComponent: {{@component name="viewComponent"}}, ' +
                    'otherViewComponent: {{@component name="anotherViewComponent"}}';

                viewComponent = new ViewComponent();

                stubNewFactory.withArgs('viewComponent').returns(viewComponent);

                viewController.render();

                expect(otherViewComponent.isDestroyed).to.be.true;

                var renderedViewsCounter = 0;

                _.each(viewController.components, function(classComponents) {
                    _.each(classComponents, function(component) {
                        if (component && component.isRendered) {
                            renderedViewsCounter += 1;
                        }
                    });
                });

                expect(renderedViewsCounter).to.be.equal(2);

            });

            it('it can be destroyed', function() {
                expect(viewController.isDestroyed).to.be.false;

                viewController.destroy();
                expect(viewController.isDestroyed).to.be.true;

                _.each(viewController.components, function(componentArray) {
                    expect(componentArray[0]).to.be.undefined;
                });
            });
        });
    });

});
<commit_msg>Added more view-controller tests<commit_after>'use strict';
/*globals require,define,describe,it, Jskeleton, before */
/* jshint unused: false */
describe('In view-controller ', function() {
    var sandbox = sinon.sandbox.create();

    before(function() {

        this.stubNewFactory = sandbox.stub(Jskeleton.factory, 'new');

        this.ViewController = Jskeleton.ViewController;

        this.createViewController = function(options) {
            return new this.ViewController(options);
        };

        this.mainRegion = new Backbone.Marionette.Region({
            el: 'body'
        });

        this.viewControllerOptions = {
            app: 'app',
            channel: 'channel',
            region: 'region'
        };
    });

    it('it exists and extends an object', function() {
        expect(this.ViewController).to.be.a('function');
        expect(this.ViewController.prototype).to.be.an('object');
    });

    it('it has all namespace properties', function() {
        expect(this.ViewController.prototype).to.include.keys(
            'constructor',
            '_ensureOptions',
            'mixinTemplateHelpers',
            'addComponent',
            'destroy',
            '_destroyComponents',
            '_delegateComponentEvent',
            '_undelegateComponentEvent',
            'unbindComponents',
            'bindComponents',
            'render'
        );
    });

    it('we can create a new view-controller object', function() {
        expect(this.createViewController.bind(this, this.viewControllerOptions)).to.not.throw(Error);
        expect(this.createViewController(this.viewControllerOptions)).to.be.instanceof(this.ViewController);
    });

    it('throws errors if we try to create a new view-controller with any option missing', function() {
        expect(this.createViewController).to.throw(Error);

        expect(this.createViewController.bind(this, {
            app: 'app',
            channel: 'channel'
        })).to.throw(Error);

        expect(this.createViewController.bind(this, {
            app: 'app',
            region: 'region'
        })).to.throw(Error);

        expect(this.createViewController.bind(this, {
            region: 'region',
            channel: 'channel'
        })).to.throw(Error);

    });

    describe('When we have a view-controller object', function() {

        beforeEach(function() {

            this.ViewComponent = Jskeleton.ItemView.extend({
                template: ' Test Title ',
                events: {
                    'click #view-action': 'onActionClicked',
                },
                onActionClicked: function(event) {
                    this.trigger('buy', event);
                }
            });

            this.OtherViewComponent = Jskeleton.ItemView.extend({
                template: ' Other Test Title ',
                events: {
                    'keypress #other-view-action': 'onActionKeypress',
                },
                onActionKeypress: function(event) {
                    this.trigger('sell', event);
                }
            });

            this.ViewController = Jskeleton.ViewController.extend({
                events: {
                    'buy @component.viewComponent': 'onLink',
                    'sell @component.otherViewComponent': 'onLink'
                },
                template: 'viewComponent: {{@component name="viewComponent"}}' +
                    'otherViewComponent: {{@component name="otherViewComponent"}}',
                onLink: function(event) {},
            });

            this.viewComponentSpyEvent = sinon.spy(this.ViewComponent.prototype,
                'onActionClicked');

            this.viewComponent = new this.ViewComponent();

            this.stubNewFactory.withArgs('viewComponent').returns(this.viewComponent);

            this.otherViewComponentSpyEvent = sinon.spy(this.OtherViewComponent.prototype,
                'onActionKeypress');

            this.otherViewComponent = new this.OtherViewComponent();

            this.stubNewFactory.withArgs('otherViewComponent').returns(this.otherViewComponent);

            this.viewController = this.createViewController(this.viewControllerOptions);

            this.viewControllerSpyEvent = sinon.spy(this.viewController, 'onLink');

        });

        it('we can add components', function() {
            expect(this.viewController.components).to.be.an('object');

            this.viewController.addComponent('ViewComponent', this.viewComponent);
            expect(Object.keys(this.viewController.components)).to.have.length.above(0);

            this.viewController.addComponent('OtherViewComponent', this.otherViewComponent);
            expect(Object.keys(this.viewController.components)).to.have.length.above(1);
        });

        describe(', rendering it in a region', function() {

            beforeEach(function() {
                this.mainRegion.show(this.viewController);
            });

            it('it is rendered', function() {
                expect(this.viewController.isRendered).to.be.true;
            });

            it('all its components are rendered', function() {
                expect(this.viewComponent.isRendered).to.be.true;
                expect(this.otherViewComponent.isRendered).to.be.true;
            });

            it('has all component events attached to it', function() {
                var self = this;
                self.componentListeners = [];

                _.each(this.viewController._listeningTo, function(listener) {
                    self.componentListeners.push(listener._listenId);
                });

                _.each(this.viewController.components, function(classComponents) {
                    _.each(classComponents, function(component) {
                        expect(_.contains(self.componentListeners, component._listenId))
                            .to.be.true;
                    });
                });
            });

            it('events run properly', function() {
                $('#view-action').click();
                $('#other-view-action').keypress();

                expect(this.viewComponentSpyEvent.calledOnce).to.be.equal(true);
                expect(this.otherViewComponentSpyEvent.calledOnce).to.be.equal(true);
                expect(this.viewControllerSpyEvent.calledTwice).to.be.equal(true);
            });

            describe(', if destroy the instance', function(){
                beforeEach(function(){
                    this.viewController.destroy();
                });

                it('the controller should be destroyed', function(){
                    expect(this.viewController.isDestroyed).to.be.true;
                });

                it('all its components should be unbinded', function(){
                    _.each(this.viewController.components, function(componentArray) {
                        _.each(componentArray, function(component) {
                            expect(component).to.be.undefined;
                        });
                    });
                });
            });

            describe(', if we refresh view-controller', function() {

                beforeEach(function() {
                    this.AnotherViewComponent = Jskeleton.ItemView.extend({
                        template: ' another Test Title ',
                    });

                    this.anotherViewComponent = new this.AnotherViewComponent();

                    this.stubNewFactory.withArgs('anotherViewComponent').returns(this.anotherViewComponent);

                    this.viewController.template = 'refresh viewComponent: {{@component name="viewComponent"}}, ' +
                        'anotherViewComponent: {{@component name="anotherViewComponent"}}';

                    this.viewComponent = new this.ViewComponent();

                    this.stubNewFactory.withArgs('viewComponent').returns(this.viewComponent);

                    this.viewController.render();
                });

                it('components are resetted', function() {
                    var self = this;

                    expect(this.otherViewComponent.isDestroyed).to.be.true;

                    self.renderedViewsCounter = 0;

                    _.each(this.viewController.components, function(classComponents) {
                        _.each(classComponents, function(component) {
                            if (component && component.isRendered) {
                                self.renderedViewsCounter += 1;
                            }
                        });
                    });

                    expect(this.renderedViewsCounter).to.be.equal(2);
                });

                it('events are delegated properly', function() {
                    $('#view-action').click();
                    expect(this.viewComponentSpyEvent.calledOnce).to.be.true;
                    expect(this.viewControllerSpyEvent.calledOnce).to.be.true;

                    $('#other-view-action').keypress();
                    expect(this.viewControllerSpyEvent.calledOnce).to.be.true;
                    expect(this.otherViewComponentSpyEvent.calledOnce).to.be.false;
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>(function() {
	var socket = io.connect();

	var SDebugger = angular.module('SDebugger', []);
	SDebugger.controller('MainCtrl', ['$scope' ,'$element' , function($scope, $element){

		$scope.logsData = [{
			logName : "Azhar",
			logs  : JSON.stringify({name : "azhar"})
		},{
			logName : "Azhar",
			logs  : JSON.stringify({name : "azhar"})
		}];

		socket.on("NEWS", function(data) {
			$scope.logsData.push(data);
			 $scope.$apply();
		});

		$scope.subscribe = function(id) {
			var userName = $scope.sDebuggerId;
			if(userName) {
				socket.emit('SUBSCRIBE', {
					userName : userName
				});
				//Storing userName into local storage
				window.localStorage.setItem('sDebuggerId', userName);
			}

		}

		$scope.deleteLog = function(index) {
			$scope.logsData.splice(index, 1)
		};

		$scope.prettifyJSON = function($event) {
			var $target = $($event.currentTarget).closest('.logsArea');
			var jsonText = $target.find("pre").text().trim();
			if(jsonText) {
				jsonText = JSON.parse(jsonText);
				$target.find("pre").html(JSON.stringify(jsonText, null, 2));
			}

		}

		$scope.sDebuggerId = window.localStorage.getItem('sDebuggerId') || "";
		if($scope.sDebuggerId) {
			$scope.subscribe();
		}

		}]);

})();

$(document).ready(function() {

	$('[data-toggle="tooltip"]').tooltip();
});<commit_msg>Test data removed<commit_after>(function() {
	var socket = io.connect();

	var SDebugger = angular.module('SDebugger', []);
	SDebugger.controller('MainCtrl', ['$scope' ,'$element' , function($scope, $element){

		$scope.logsData = [];

		socket.on("NEWS", function(data) {
			$scope.logsData.push(data);
			 $scope.$apply();
		});

		$scope.subscribe = function(id) {
			var userName = $scope.sDebuggerId;
			if(userName) {
				socket.emit('SUBSCRIBE', {
					userName : userName
				});
				//Storing userName into local storage
				window.localStorage.setItem('sDebuggerId', userName);
			}

		}

		$scope.deleteLog = function(index) {
			$scope.logsData.splice(index, 1)
		};

		$scope.prettifyJSON = function($event) {
			var $target = $($event.currentTarget).closest('.logsArea');
			var jsonText = $target.find("pre").text().trim();
			if(jsonText) {
				jsonText = JSON.parse(jsonText);
				$target.find("pre").html(JSON.stringify(jsonText, null, 2));
			}

		}

		$scope.sDebuggerId = window.localStorage.getItem('sDebuggerId') || "";
		if($scope.sDebuggerId) {
			$scope.subscribe();
		}

		}]);

})();

$(document).ready(function() {

	$('[data-toggle="tooltip"]').tooltip();
});<|endoftext|>


<commit_before>import fs from 'fs';
import path from 'path';
import {markdown} from './util.js';

/**
 * Resolve various properties in doc object.
 */
export default class DocResolver {
  /**
   * create instance.
   * @param {DocBuilder} builder - target doc builder.
   */
  constructor(builder) {
    this._builder = builder;
    this._data = builder._data;
  }

  /**
   * resolve various properties.
   */
  resolve() {
    this._resolveExtendsChain();
    this._resolveNecessary();
    this._resolveAccess();
    this._resolveUnexportIdentifier();
    this._resolveUndocumentIdentifier();
    this._resolveDuplication();
    this._resolveIgnore();
    this._resolveLink();
    this._resolveMarkdown();
    this._resolveTestRelation();
  }

  /**
   * resolve ignore property.
   * remove docs that has ignore property.
   * @private
   */
  _resolveIgnore() {
    if (this._data.__RESOLVED_IGNORE__) return;

    let docs = this._builder._find({ignore: true});
    for (let doc of docs) {
      let longname = doc.longname.replace(/[$]/g, '\\$');
      let regex = new RegExp(`^${longname}[.~#]`);
      this._data({longname: {regex: regex}}).remove();
    }
    this._data({ignore: true}).remove();

    this._data.__RESOLVED_IGNORE__ = true;
  }

  /**
   * resolve access property.
   * if doc does not have access property, the doc is public.
   * but name is started with '-', the doc is private.
   * @private
   */
  _resolveAccess() {
    if (this._data.__RESOLVED_ACCESS__) return;

    let config = this._builder._config;
    let access = config.access || ['public', 'protected', 'private'];
    let autoPrivate = config.autoPrivate;

    this._data().update(function(){
      if (!this.access) {
        if (autoPrivate && this.name.charAt(0) === '_') {
          /** @ignore */
          this.access = 'private';
        } else {
          this.access = 'public';
        }
      }

      if (!access.includes(this.access)) /** @ignore */ this.ignore = true;

      return this;
    });

    this._data.__RESOLVED_ACCESS__ = true;
  }

  /**
   * resolve unexport identifier doc.
   * doc is added ignore property that is not exported.
   * @private
   */
  _resolveUnexportIdentifier() {
    if (this._data.__RESOLVED_UNEXPORT_IDENTIFIER__) return;

    let config = this._builder._config;
    if (!config.unexportIdentifier) {
      this._data({export: false}).update({ignore: true});
    }

    this._data.__RESOLVED_UNEXPORT_IDENTIFIER__ = true;
  }

  /**
   * resolve undocument identifier doc.
   * doc is added ignore property that does not have document tag.
   * @private
   */
  _resolveUndocumentIdentifier() {
    if (this._data.__RESOLVED_UNDOCUMENT_IDENTIFIER__) return;

    if (!this._builder._config.undocumentIdentifier) {
      this._builder._data({undocument: true}).update({ignore: true});
    }

    this._data.__RESOLVED_UNDOCUMENT_IDENTIFIER__ = true;
  }

  /**
   * resolve description as markdown.
   * @private
   */
  _resolveMarkdown() {
    if (this._data.__RESOLVED_MARKDOWN__) return;

    function convert(obj) {
      for (let key of Object.keys(obj)) {
        let value = obj[key];
        if (key === 'description' && typeof value === 'string') {
          obj[key + 'Raw'] = obj[key];
          obj[key] = markdown(value, false);
        } else if (typeof value === 'object' && value) {
          convert(value);
        }
      }
    }

    let docs = this._builder._find();
    for (let doc of docs) {
      convert(doc);
    }

    this._data.__RESOLVED_MARKDOWN__ = true;
  }

  /**
   * resolve @link as html link.
   * @private
   * @todo resolve all ``description`` property.
   */
  _resolveLink() {
    if(this._data.__RESOLVED_LINK__) return;

    let link = (str)=>{
      if (!str) return str;

      return str.replace(/\{@link ([\w\#_\-.:\~\/$]+)}/g, (str, longname)=>{
        return this._builder._buildDocLinkHTML(longname, longname);
      });
    };

    this._data().each((v)=>{
      v.description = link(v.description);

      if (v.params) {
        for (let param of v.params) {
          param.description = link(param.description);
        }
      }

      if (v.return) {
        v.return.description = link(v.return.description);
      }

      if (v.throws) {
        for (let _throw of v.throws) {
          _throw.description = link(_throw.description);
        }
      }

      if (v.see) {
        for (let i = 0; i < v.see.length; i++) {
          if (v.see[i].indexOf('{@link') === 0) {
            v.see[i] = link(v.see[i]);
          } else if(v.see[i].indexOf('<a href') === 0) {
            // ignore
          } else {
            v.see[i] = `<a href="${v.see[i]}">${v.see[i]}</a>`;
          }
        }
      }
    });

    this._data.__RESOLVED_LINK__ = true;
  }

  /**
   * resolve class extends chain.
   * add following special property.
   * - ``_custom_extends_chain``: ancestor class chain.
   * - ``_custom_direct_subclasses``: class list that direct extends target doc.
   * - ``_custom_indirect_subclasses``: class list that indirect extends target doc.
   * - ``_custom_indirect_implements``: class list that target doc indirect implements.
   * - ``_custom_direct_implemented``: class list that direct implements target doc.
   * - ``_custom_indirect_implemented``: class list that indirect implements target doc.
   *
   * @private
   */
  _resolveExtendsChain() {
    if (this._data.__RESOLVED_EXTENDS_CHAIN__) return;

    let extendsChain = (doc) => {
      if (!doc.extends) return;

      let selfDoc = doc;

      // traverse super class.
      let chains = [];
      while (1) {
        if (!doc.extends) break;

        let superClassDoc = this._builder._findByName(doc.extends[0])[0];
        if (superClassDoc) {
          chains.push(superClassDoc.longname);
          doc = superClassDoc;
        } else {
          chains.push(doc.extends[0]);
          break;
        }
      }

      if (chains.length) {
        // direct subclass
        let superClassDoc = this._builder._findByName(chains[0])[0];
        if (superClassDoc) {
          if (!superClassDoc._custom_direct_subclasses) superClassDoc._custom_direct_subclasses = [];
          superClassDoc._custom_direct_subclasses.push(selfDoc.longname);
        }

        // indirect subclass
        for (let superClassLongname of chains.slice(1)) {
          superClassDoc = this._builder._findByName(superClassLongname)[0];
          if (superClassDoc) {
            if (!superClassDoc._custom_indirect_subclasses) superClassDoc._custom_indirect_subclasses = [];
            superClassDoc._custom_indirect_subclasses.push(selfDoc.longname);
          }
        }

        // indirect implements and mixes
        for (let superClassLongname of chains) {
          superClassDoc = this._builder._findByName(superClassLongname)[0];
          if (!superClassDoc) continue;

          // indirect implements
          if (superClassDoc.implements) {
            if (!selfDoc._custom_indirect_implements) selfDoc._custom_indirect_implements = [];
            selfDoc._custom_indirect_implements.push(...superClassDoc.implements);
          }

          // indirect mixes
          //if (superClassDoc.mixes) {
          //  if (!selfDoc._custom_indirect_mixes) selfDoc._custom_indirect_mixes = [];
          //  selfDoc._custom_indirect_mixes.push(...superClassDoc.mixes);
          //}
        }

        // extends chains
        selfDoc._custom_extends_chains = chains.reverse();
      }
    };

    let implemented = (doc) =>{
      let selfDoc = doc;

      // direct implemented (like direct subclass)
      for (let superClassLongname of selfDoc.implements || []) {
        let superClassDoc = this._builder._findByName(superClassLongname)[0];
        if (!superClassDoc) continue;
        if(!superClassDoc._custom_direct_implemented) superClassDoc._custom_direct_implemented = [];
        superClassDoc._custom_direct_implemented.push(selfDoc.longname);
      }

      // indirect implemented (like indirect subclass)
      for (let superClassLongname of selfDoc._custom_indirect_implements || []) {
        let superClassDoc = this._builder._findByName(superClassLongname)[0];
        if (!superClassDoc) continue;
        if(!superClassDoc._custom_indirect_implemented) superClassDoc._custom_indirect_implemented = [];
        superClassDoc._custom_indirect_implemented.push(selfDoc.longname);
      }
    };

    //var mixed = (doc) =>{
    //  var selfDoc = doc;
    //
    //  // direct mixed (like direct subclass)
    //  for (var superClassLongname of selfDoc.mixes || []) {
    //    var superClassDoc = this._builder._find({longname: superClassLongname})[0];
    //    if (!superClassDoc) continue;
    //    if(!superClassDoc._custom_direct_mixed) superClassDoc._custom_direct_mixed = [];
    //    superClassDoc._custom_direct_mixed.push(selfDoc.longname);
    //  }
    //
    //  // indirect mixed (like indirect subclass)
    //  for (var superClassLongname of selfDoc._custom_indirect_mixes || []) {
    //    var superClassDoc = this._builder._find({longname: superClassLongname})[0];
    //    if (!superClassDoc) continue;
    //    if(!superClassDoc._custom_indirect_mixed) superClassDoc._custom_indirect_mixed = [];
    //    superClassDoc._custom_indirect_mixed.push(selfDoc.longname);
    //  }
    //};

    let docs = this._builder._find({kind: 'class'});
    for (let doc of docs) {
      extendsChain(doc);
      implemented(doc);
      //mixed(doc);
    }

    this._data.__RESOLVED_EXTENDS_CHAIN__ = true;
  }

  /**
   * resolve necessary identifier.
   *
   * ```javascript
   * class Foo {}
   *
   * export default Bar extends Foo {}
   * ```
   *
   * ``Foo`` is not exported, but ``Bar`` extends ``Foo``.
   * ``Foo`` is necessary.
   * So, ``Foo`` must be exported by force.
   *
   * @private
   */
  _resolveNecessary() {
    let builder = this._builder;
    this._data({export: false}).update(function() {
      let doc = this;
      let childNames = [];
      if (doc._custom_direct_subclasses) childNames.push(...doc._custom_direct_subclasses);
      if (doc._custom_indirect_subclasses) childNames.push(...doc._custom_indirect_subclasses);
      if (doc._custom_direct_implemented) childNames.push(...doc._custom_direct_implemented);
      if (doc._custom_indirect_implemented) childNames.push(...doc._custom_indirect_implemented);

      for (let childName of childNames) {
        let childDoc = builder._find({longname: childName})[0];
        if (!childDoc) continue;
        if (!childDoc.ignore && childDoc.export) {
          doc.export = true;
          return doc;
        }
      }
    });
  }

  /**
   * resolve test and identifier relation. add special property.
   * - ``_custom_tests``: longnames of test doc.
   * - ``_custom_test_targets``: longnames of identifier.
   *
   * @private
   */
  _resolveTestRelation() {
    if (this._data.__RESOLVED_TEST_RELATION__) return;

    let testDocs = this._builder._find({kind: ['testDescribe', 'testIt']});
    for (let testDoc of testDocs) {
      let testTargets = testDoc.testTargets;
      if (!testTargets) continue;

      for (let testTarget of testTargets) {
        let doc = this._builder._findByName(testTarget)[0];
        if (doc) {
          if (!doc._custom_tests) doc._custom_tests = [];
          doc._custom_tests.push(testDoc.longname);

          if (!testDoc._custom_test_targets) testDoc._custom_test_targets = [];
          testDoc._custom_test_targets.push([doc.longname, testTarget]);
        } else {
          if (!testDoc._custom_test_targets) testDoc._custom_test_targets = [];
          testDoc._custom_test_targets.push([testTarget, testTarget]);
        }
      }
    }

    // test full description
    for (let testDoc of testDocs) {
      let desc = [];
      let parents = (testDoc.memberof.split('~')[1] || '').split('.');
      for (let parent of parents) {
        let doc = this._builder._find({kind: ['testDescribe', 'testIt'], name: parent})[0];
        if (!doc) continue;
        desc.push(doc.descriptionRaw);
      }
      desc.push(testDoc.descriptionRaw);
      testDoc.testFullDescription = desc.join(' ');
    }

    this._data.__RESOLVED_TEST_RELATION__ = true;
  }

  /**
   * resolve duplication identifier.
   * member doc is possible duplication.
   * other doc is not duplication.
   * @private
   */
  _resolveDuplication() {
    if (this._data.__RESOLVED_DUPLICATION__) return;

    let docs = this._builder._find({kind: 'member'});
    let ignoreId = [];
    for (let doc of docs) {
      // member duplicate with getter/setter/method.
      // when it, remove member.
      // getter/setter/method are high priority.
      const nonMemberDup = this._builder._find({longname: doc.longname, kind: {'!is': 'member'}});
      if (nonMemberDup.length) {
        ignoreId.push(doc.___id);
        continue;
      }

      let dup = this._builder._find({longname: doc.longname, kind: 'member'});
      if (dup.length > 1) {
        let ids = dup.map(v => v.___id);
        ids.sort((a, b)=> {
          return a < b ? -1 : 1;
        });
        ids.shift();
        ignoreId.push(...ids)
      }
    }

    this._data({___id: ignoreId}).update(function(){
      this.ignore = true;
      return this;
    });

    this._data.__RESOLVED_DUPLICATION__ = true;
  }
}
<commit_msg>fix(resolver): not work @link at property<commit_after>import fs from 'fs';
import path from 'path';
import {markdown} from './util.js';

/**
 * Resolve various properties in doc object.
 */
export default class DocResolver {
  /**
   * create instance.
   * @param {DocBuilder} builder - target doc builder.
   */
  constructor(builder) {
    this._builder = builder;
    this._data = builder._data;
  }

  /**
   * resolve various properties.
   */
  resolve() {
    this._resolveExtendsChain();
    this._resolveNecessary();
    this._resolveAccess();
    this._resolveUnexportIdentifier();
    this._resolveUndocumentIdentifier();
    this._resolveDuplication();
    this._resolveIgnore();
    this._resolveLink();
    this._resolveMarkdown();
    this._resolveTestRelation();
  }

  /**
   * resolve ignore property.
   * remove docs that has ignore property.
   * @private
   */
  _resolveIgnore() {
    if (this._data.__RESOLVED_IGNORE__) return;

    let docs = this._builder._find({ignore: true});
    for (let doc of docs) {
      let longname = doc.longname.replace(/[$]/g, '\\$');
      let regex = new RegExp(`^${longname}[.~#]`);
      this._data({longname: {regex: regex}}).remove();
    }
    this._data({ignore: true}).remove();

    this._data.__RESOLVED_IGNORE__ = true;
  }

  /**
   * resolve access property.
   * if doc does not have access property, the doc is public.
   * but name is started with '-', the doc is private.
   * @private
   */
  _resolveAccess() {
    if (this._data.__RESOLVED_ACCESS__) return;

    let config = this._builder._config;
    let access = config.access || ['public', 'protected', 'private'];
    let autoPrivate = config.autoPrivate;

    this._data().update(function(){
      if (!this.access) {
        if (autoPrivate && this.name.charAt(0) === '_') {
          /** @ignore */
          this.access = 'private';
        } else {
          this.access = 'public';
        }
      }

      if (!access.includes(this.access)) /** @ignore */ this.ignore = true;

      return this;
    });

    this._data.__RESOLVED_ACCESS__ = true;
  }

  /**
   * resolve unexport identifier doc.
   * doc is added ignore property that is not exported.
   * @private
   */
  _resolveUnexportIdentifier() {
    if (this._data.__RESOLVED_UNEXPORT_IDENTIFIER__) return;

    let config = this._builder._config;
    if (!config.unexportIdentifier) {
      this._data({export: false}).update({ignore: true});
    }

    this._data.__RESOLVED_UNEXPORT_IDENTIFIER__ = true;
  }

  /**
   * resolve undocument identifier doc.
   * doc is added ignore property that does not have document tag.
   * @private
   */
  _resolveUndocumentIdentifier() {
    if (this._data.__RESOLVED_UNDOCUMENT_IDENTIFIER__) return;

    if (!this._builder._config.undocumentIdentifier) {
      this._builder._data({undocument: true}).update({ignore: true});
    }

    this._data.__RESOLVED_UNDOCUMENT_IDENTIFIER__ = true;
  }

  /**
   * resolve description as markdown.
   * @private
   */
  _resolveMarkdown() {
    if (this._data.__RESOLVED_MARKDOWN__) return;

    function convert(obj) {
      for (let key of Object.keys(obj)) {
        let value = obj[key];
        if (key === 'description' && typeof value === 'string') {
          obj[key + 'Raw'] = obj[key];
          obj[key] = markdown(value, false);
        } else if (typeof value === 'object' && value) {
          convert(value);
        }
      }
    }

    let docs = this._builder._find();
    for (let doc of docs) {
      convert(doc);
    }

    this._data.__RESOLVED_MARKDOWN__ = true;
  }

  /**
   * resolve @link as html link.
   * @private
   * @todo resolve all ``description`` property.
   */
  _resolveLink() {
    if(this._data.__RESOLVED_LINK__) return;

    let link = (str)=>{
      if (!str) return str;

      return str.replace(/\{@link ([\w\#_\-.:\~\/$]+)}/g, (str, longname)=>{
        return this._builder._buildDocLinkHTML(longname, longname);
      });
    };

    this._data().each((v)=>{
      v.description = link(v.description);

      if (v.params) {
        for (let param of v.params) {
          param.description = link(param.description);
        }
      }

      if (v.properties) {
        for (let property of v.properties) {
          property.description = link(property.description);
        }
      }

      if (v.return) {
        v.return.description = link(v.return.description);
      }

      if (v.throws) {
        for (let _throw of v.throws) {
          _throw.description = link(_throw.description);
        }
      }

      if (v.see) {
        for (let i = 0; i < v.see.length; i++) {
          if (v.see[i].indexOf('{@link') === 0) {
            v.see[i] = link(v.see[i]);
          } else if(v.see[i].indexOf('<a href') === 0) {
            // ignore
          } else {
            v.see[i] = `<a href="${v.see[i]}">${v.see[i]}</a>`;
          }
        }
      }
    });

    this._data.__RESOLVED_LINK__ = true;
  }

  /**
   * resolve class extends chain.
   * add following special property.
   * - ``_custom_extends_chain``: ancestor class chain.
   * - ``_custom_direct_subclasses``: class list that direct extends target doc.
   * - ``_custom_indirect_subclasses``: class list that indirect extends target doc.
   * - ``_custom_indirect_implements``: class list that target doc indirect implements.
   * - ``_custom_direct_implemented``: class list that direct implements target doc.
   * - ``_custom_indirect_implemented``: class list that indirect implements target doc.
   *
   * @private
   */
  _resolveExtendsChain() {
    if (this._data.__RESOLVED_EXTENDS_CHAIN__) return;

    let extendsChain = (doc) => {
      if (!doc.extends) return;

      let selfDoc = doc;

      // traverse super class.
      let chains = [];
      while (1) {
        if (!doc.extends) break;

        let superClassDoc = this._builder._findByName(doc.extends[0])[0];
        if (superClassDoc) {
          chains.push(superClassDoc.longname);
          doc = superClassDoc;
        } else {
          chains.push(doc.extends[0]);
          break;
        }
      }

      if (chains.length) {
        // direct subclass
        let superClassDoc = this._builder._findByName(chains[0])[0];
        if (superClassDoc) {
          if (!superClassDoc._custom_direct_subclasses) superClassDoc._custom_direct_subclasses = [];
          superClassDoc._custom_direct_subclasses.push(selfDoc.longname);
        }

        // indirect subclass
        for (let superClassLongname of chains.slice(1)) {
          superClassDoc = this._builder._findByName(superClassLongname)[0];
          if (superClassDoc) {
            if (!superClassDoc._custom_indirect_subclasses) superClassDoc._custom_indirect_subclasses = [];
            superClassDoc._custom_indirect_subclasses.push(selfDoc.longname);
          }
        }

        // indirect implements and mixes
        for (let superClassLongname of chains) {
          superClassDoc = this._builder._findByName(superClassLongname)[0];
          if (!superClassDoc) continue;

          // indirect implements
          if (superClassDoc.implements) {
            if (!selfDoc._custom_indirect_implements) selfDoc._custom_indirect_implements = [];
            selfDoc._custom_indirect_implements.push(...superClassDoc.implements);
          }

          // indirect mixes
          //if (superClassDoc.mixes) {
          //  if (!selfDoc._custom_indirect_mixes) selfDoc._custom_indirect_mixes = [];
          //  selfDoc._custom_indirect_mixes.push(...superClassDoc.mixes);
          //}
        }

        // extends chains
        selfDoc._custom_extends_chains = chains.reverse();
      }
    };

    let implemented = (doc) =>{
      let selfDoc = doc;

      // direct implemented (like direct subclass)
      for (let superClassLongname of selfDoc.implements || []) {
        let superClassDoc = this._builder._findByName(superClassLongname)[0];
        if (!superClassDoc) continue;
        if(!superClassDoc._custom_direct_implemented) superClassDoc._custom_direct_implemented = [];
        superClassDoc._custom_direct_implemented.push(selfDoc.longname);
      }

      // indirect implemented (like indirect subclass)
      for (let superClassLongname of selfDoc._custom_indirect_implements || []) {
        let superClassDoc = this._builder._findByName(superClassLongname)[0];
        if (!superClassDoc) continue;
        if(!superClassDoc._custom_indirect_implemented) superClassDoc._custom_indirect_implemented = [];
        superClassDoc._custom_indirect_implemented.push(selfDoc.longname);
      }
    };

    //var mixed = (doc) =>{
    //  var selfDoc = doc;
    //
    //  // direct mixed (like direct subclass)
    //  for (var superClassLongname of selfDoc.mixes || []) {
    //    var superClassDoc = this._builder._find({longname: superClassLongname})[0];
    //    if (!superClassDoc) continue;
    //    if(!superClassDoc._custom_direct_mixed) superClassDoc._custom_direct_mixed = [];
    //    superClassDoc._custom_direct_mixed.push(selfDoc.longname);
    //  }
    //
    //  // indirect mixed (like indirect subclass)
    //  for (var superClassLongname of selfDoc._custom_indirect_mixes || []) {
    //    var superClassDoc = this._builder._find({longname: superClassLongname})[0];
    //    if (!superClassDoc) continue;
    //    if(!superClassDoc._custom_indirect_mixed) superClassDoc._custom_indirect_mixed = [];
    //    superClassDoc._custom_indirect_mixed.push(selfDoc.longname);
    //  }
    //};

    let docs = this._builder._find({kind: 'class'});
    for (let doc of docs) {
      extendsChain(doc);
      implemented(doc);
      //mixed(doc);
    }

    this._data.__RESOLVED_EXTENDS_CHAIN__ = true;
  }

  /**
   * resolve necessary identifier.
   *
   * ```javascript
   * class Foo {}
   *
   * export default Bar extends Foo {}
   * ```
   *
   * ``Foo`` is not exported, but ``Bar`` extends ``Foo``.
   * ``Foo`` is necessary.
   * So, ``Foo`` must be exported by force.
   *
   * @private
   */
  _resolveNecessary() {
    let builder = this._builder;
    this._data({export: false}).update(function() {
      let doc = this;
      let childNames = [];
      if (doc._custom_direct_subclasses) childNames.push(...doc._custom_direct_subclasses);
      if (doc._custom_indirect_subclasses) childNames.push(...doc._custom_indirect_subclasses);
      if (doc._custom_direct_implemented) childNames.push(...doc._custom_direct_implemented);
      if (doc._custom_indirect_implemented) childNames.push(...doc._custom_indirect_implemented);

      for (let childName of childNames) {
        let childDoc = builder._find({longname: childName})[0];
        if (!childDoc) continue;
        if (!childDoc.ignore && childDoc.export) {
          doc.export = true;
          return doc;
        }
      }
    });
  }

  /**
   * resolve test and identifier relation. add special property.
   * - ``_custom_tests``: longnames of test doc.
   * - ``_custom_test_targets``: longnames of identifier.
   *
   * @private
   */
  _resolveTestRelation() {
    if (this._data.__RESOLVED_TEST_RELATION__) return;

    let testDocs = this._builder._find({kind: ['testDescribe', 'testIt']});
    for (let testDoc of testDocs) {
      let testTargets = testDoc.testTargets;
      if (!testTargets) continue;

      for (let testTarget of testTargets) {
        let doc = this._builder._findByName(testTarget)[0];
        if (doc) {
          if (!doc._custom_tests) doc._custom_tests = [];
          doc._custom_tests.push(testDoc.longname);

          if (!testDoc._custom_test_targets) testDoc._custom_test_targets = [];
          testDoc._custom_test_targets.push([doc.longname, testTarget]);
        } else {
          if (!testDoc._custom_test_targets) testDoc._custom_test_targets = [];
          testDoc._custom_test_targets.push([testTarget, testTarget]);
        }
      }
    }

    // test full description
    for (let testDoc of testDocs) {
      let desc = [];
      let parents = (testDoc.memberof.split('~')[1] || '').split('.');
      for (let parent of parents) {
        let doc = this._builder._find({kind: ['testDescribe', 'testIt'], name: parent})[0];
        if (!doc) continue;
        desc.push(doc.descriptionRaw);
      }
      desc.push(testDoc.descriptionRaw);
      testDoc.testFullDescription = desc.join(' ');
    }

    this._data.__RESOLVED_TEST_RELATION__ = true;
  }

  /**
   * resolve duplication identifier.
   * member doc is possible duplication.
   * other doc is not duplication.
   * @private
   */
  _resolveDuplication() {
    if (this._data.__RESOLVED_DUPLICATION__) return;

    let docs = this._builder._find({kind: 'member'});
    let ignoreId = [];
    for (let doc of docs) {
      // member duplicate with getter/setter/method.
      // when it, remove member.
      // getter/setter/method are high priority.
      const nonMemberDup = this._builder._find({longname: doc.longname, kind: {'!is': 'member'}});
      if (nonMemberDup.length) {
        ignoreId.push(doc.___id);
        continue;
      }

      let dup = this._builder._find({longname: doc.longname, kind: 'member'});
      if (dup.length > 1) {
        let ids = dup.map(v => v.___id);
        ids.sort((a, b)=> {
          return a < b ? -1 : 1;
        });
        ids.shift();
        ignoreId.push(...ids)
      }
    }

    this._data({___id: ignoreId}).update(function(){
      this.ignore = true;
      return this;
    });

    this._data.__RESOLVED_DUPLICATION__ = true;
  }
}
<|endoftext|>


<commit_before>/**
 * @file TipProvider component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, isValidElement, cloneElement, Fragment} from 'react';
import PropTypes from 'prop-types';
import {findDOMNode} from 'react-dom';
import classNames from 'classnames';

import Tip from '../Tip';
import Theme from '../Theme';

import Util from '../_vendors/Util';

class TipProvider extends Component {

    static Position = Tip.Position;
    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            tipVisible: false
        };

    }

    showTip = () => {
        if (!this.state.tipVisible) {
            this.setState({
                tipVisible: true
            });
        }
    };

    hideTip = () => {
        this.setState({
            tipVisible: false
        });
    };

    componentDidMount() {
        this.refs.trigger && (this.triggerEl = findDOMNode(this.refs.trigger));
    }

    render() {

        const {children, text, onTipRender, ...restProps} = this.props,
            {tipVisible} = this.state;

        if (!text) {
            return children;
        }

        return (
            <Fragment>

                {
                    cloneElement(children, {
                        ref: 'trigger',
                        onMouseOver: e => {

                            if (children && children.props && children.props.onMouseOver
                                && typeof children.props.onMouseOver === 'function') {
                                children.props.onMouseOver(e);
                            }

                            this.showTip();

                        },
                        onMouseOut: e => {

                            if (children && children.props && children.props.onMouseOut
                                && typeof children.props.onMouseOut === 'function') {
                                children.props.onMouseOut(e);
                            }

                            this.hideTip();

                        }
                    })
                }

                <Tip {...restProps}
                     triggerEl={this.triggerEl}
                     visible={tipVisible}
                     onRender={onTipRender}>
                    {text}
                </Tip>

            </Fragment>
        );
    }

}

TipProvider.propTypes = {

    /**
     * The CSS class name of the tip element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * If true,the popover will have a triangle on the top of the DOM element.
     */
    hasTriangle: PropTypes.bool,

    triangle: PropTypes.element,

    /**
     * The popover theme.Can be primary,highlight,success,warning,error.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The popover alignment.
     */
    position: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

    /**
     * If true, menu will have animation effects.
     */
    isAnimated: PropTypes.bool,

    shouldPreventContainerScroll: PropTypes.bool,

    /**
     * The depth of Paper component.
     */
    depth: PropTypes.number,

    isTriggerPositionFixed: PropTypes.bool,

    /**
     * The function of tip render.
     */
    onTipRender: PropTypes.func,

    /**
     * Callback function fired when wrapper wheeled.
     */
    onWheel: PropTypes.func,

    text: PropTypes.any

};

TipProvider.defaultProps = {

    theme: Theme.DARK,

    hasTriangle: true,
    position: Tip.Position.BOTTOM,
    isAnimated: true,
    shouldPreventContainerScroll: true,
    isTriggerPositionFixed: false

};

export default TipProvider;
<commit_msg>update TipProvider<commit_after>/**
 * @file TipProvider component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, isValidElement, cloneElement, Fragment} from 'react';
import PropTypes from 'prop-types';
import {findDOMNode} from 'react-dom';
import classNames from 'classnames';

import Tip from '../Tip';
import Theme from '../Theme';

import Util from '../_vendors/Util';
import Position from '../_statics/Position';

class TipProvider extends Component {

    static Position = Tip.Position;
    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            visible: props.visible
        };

    }

    showTip = () => {
        if (!this.state.visible) {
            this.setState({
                visible: true
            });
        }
    };

    hideTip = () => {
        this.setState({
            visible: false
        });
    };

    componentDidMount() {
        this.refs.trigger && (this.triggerEl = findDOMNode(this.refs.trigger));
    }

    render() {

        const {children, text, onTipRender, ...restProps} = this.props,
            {visible} = this.state;

        if (!text) {
            return children;
        }

        return (
            <Fragment>

                {
                    cloneElement(children, {
                        ref: 'trigger',
                        onMouseOver: e => {

                            if (children && children.props && children.props.onMouseOver
                                && typeof children.props.onMouseOver === 'function') {
                                children.props.onMouseOver(e);
                            }

                            this.showTip();

                        },
                        onMouseOut: e => {

                            if (children && children.props && children.props.onMouseOut
                                && typeof children.props.onMouseOut === 'function') {
                                children.props.onMouseOut(e);
                            }

                            this.hideTip();

                        }
                    })
                }

                <Tip {...restProps}
                     triggerEl={this.triggerEl}
                     visible={visible}
                     onRender={onTipRender}>
                    {text}
                </Tip>

            </Fragment>
        );
    }

}

TipProvider.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The CSS class name of the content element.
     */
    contentClassName: PropTypes.string,

    modalClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The popover theme.Can be primary,highlight,success,warning,error.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * This is the DOM element that will be used to set the position of the popover.
     */
    triggerEl: PropTypes.object,

    /**
     * If true,the popover is visible.
     */
    visible: PropTypes.bool,

    /**
     * If true,the popover will have a triangle on the top of the DOM element.
     */
    hasTriangle: PropTypes.bool,

    triangle: PropTypes.element,

    /**
     * The popover alignment.
     */
    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * If true, menu will have animation effects.
     */
    isAnimated: PropTypes.bool,

    shouldPreventContainerScroll: PropTypes.bool,

    /**
     * The depth of Paper component.
     */
    depth: PropTypes.number,

    isTriggerPositionFixed: PropTypes.bool,
    resetPositionWait: PropTypes.number,
    showModal: PropTypes.bool,

    /**
     * The function of tip render.
     */
    onRender: PropTypes.func,

    /**
     * The function of tip rendered.
     */
    onRendered: PropTypes.func,

    /**
     * The function of tip destroy.
     */
    onDestroy: PropTypes.func,

    /**
     * The function of tip destroyed.
     */
    onDestroyed: PropTypes.func,

    /**
     * Callback function fired when wrapper wheeled.
     */
    onWheel: PropTypes.func

};

TipProvider.defaultProps = {

    theme: Theme.DARK,

    visible: false,
    hasTriangle: true,
    position: Position.BOTTOM,
    isAnimated: true,
    shouldPreventContainerScroll: true,
    isTriggerPositionFixed: false,
    resetPositionWait: 250,
    showModal: false

};

export default TipProvider;
<|endoftext|>


<commit_before>app.controller('PresentationCtrl',function ($scope, $stateParams, Session, PresentationFactory, ConferenceFactory, presentations, conferences) {
    $scope.showImages = false;
    $scope.presentations = presentations;  // resolve method
    $scope.conferenceOptions = conferences;   // resolve method
  //  $scope.localesOptions = locales  // resolve method
    $scope.currentPresentationId = null;

    $scope.displayPresentationMedia = function(id){
        console.log('presentations: ', $scope.presentations);
        $scope.presentationMedia = _.find($scope.presentations, {_id: id}).media;  // !!! creates a reference
        if ($scope.presentationMedia.length === 0 ) {
            $scope.presentationMedia.push({
                mediaType: 'image',
                url: 'Begin adding slides to your presentation! You can delete this message once you\'ve done that!'
            });
        }
        $scope.currentPresentationId = id;
    };

    // corresponding $scope.presentations.media array is also spliced when removeCard runs (see displayPresentationMedia)
    $scope.removeCard = function (index) {
        $scope.presentationMedia.splice(index,1);
    };

    $scope.savePresentation = function() {
        PresentationFactory.savePresentation($scope.currentPresentationId, $scope.presentationMedia);
    };

    $scope.toggleImages = function(){
        $scope.showImages = $scope.showImages ? false : true;
    };

    $scope.sortableOptions = {
        additionPlaceholderClass: 'presentation-a-s'
    };

    // functionality for creating a new presentation
    $scope.showCreateForm = function () {
        $scope.creating = true;
    };

    $scope.closeCreateForm = function () {
        $scope.creating = false;
        refreshPresentationObj();
    };

    function refreshPresentationObj () {   // refresh $scope.newPresentation object
        $scope.newPresentation = {
            title: '',
            presenter: null,
            media: []
        };
    }

    $scope.newPresentation = {
        title: '',
        presenter: null,
        media: []
    };

    // creating a presentation also adds the user as a presenter to a particular conference
    // creating a presentation merely adds it to the db; it does not initally contain media
    $scope.createPresentation = function (conference_id) {
        $scope.creating = false;    // to hide the input box
        return PresentationFactory.createPresentation($scope.newPresentation)
                .then(function (newPresentation) {
                    $scope.presentations.push(newPresentation);
                    refreshPresentationObj();
                    return ConferenceFactory.addConferencePresenter(conference_id, Session.user._id);
                })
                .then(function (conference) {
                    console.log('added the user to this conference as a presenter: ', conference);
                    // should something else happen here on the ui?
                });
    };

    // functionality for removing a presentation goes here
    $scope.checkboxModel = {};   // tracks all the checkboxes

    $scope.deletePresentations = function () {
        console.log($scope.checkboxModel);
        var idsToDelete = [], deleted_ids = [];
        angular.forEach($scope.checkboxModel, function(value, checkbox_id) {
            if (value === true) {         // i.e. checkbox is checked
                this.push(checkbox_id);      // push in checkbox_id which is the presentation id
            }
        }, idsToDelete);
        console.log('ids of conferences to delete: ', idsToDelete);
        PresentationFactory.deletePresentations(idsToDelete)
        .then(function (deletedPromises) {
                angular.forEach(deletedPromises, function (response) {
                    deleted_ids.push(response.data._id);
                });
            console.log('deleted presentations: ', deleted_ids);
            $scope.presentations = _.remove($scope.presentations, function (item) {
                return deleted_ids.indexOf(item._id) == -1;
            });
            // affect the checkbox model - use lodash?
            //$scope.checkboxModel = something;

        });
        // fire off factory method to delete presentations (promises)
        // must then refresh the checkbox model and clear it of all keys once deletion is complete

        // should the function also check for the relevant conference and delete the user from the presenters array?
        // Wesley says - "no"
    };
});<commit_msg>presentations deletable<commit_after>app.controller('PresentationCtrl',function ($scope, $stateParams, Session, PresentationFactory, ConferenceFactory, presentations, conferences) {
    $scope.showImages = false;
    $scope.presentations = presentations;  // resolve method
    $scope.conferenceOptions = conferences;   // resolve method
  //  $scope.localesOptions = locales  // resolve method
    $scope.currentPresentationId = null;

    $scope.displayPresentationMedia = function(id){
        console.log('presentations: ', $scope.presentations);
        $scope.presentationMedia = _.find($scope.presentations, {_id: id}).media;  // !!! creates a reference
        if ($scope.presentationMedia.length === 0 ) {
            $scope.presentationMedia.push({
                mediaType: 'image',
                url: 'Begin adding slides to your presentation! You can delete this message once you\'ve done that!'
            });
        }
        $scope.currentPresentationId = id;
    };

    // corresponding $scope.presentations.media array is also spliced when removeCard runs (see displayPresentationMedia)
    $scope.removeCard = function (index) {
        $scope.presentationMedia.splice(index,1);
    };

    $scope.savePresentation = function() {
        PresentationFactory.savePresentation($scope.currentPresentationId, $scope.presentationMedia);
    };

    $scope.toggleImages = function(){
        $scope.showImages = $scope.showImages ? false : true;
    };

    $scope.sortableOptions = {
        additionPlaceholderClass: 'presentation-a-s'
    };

    // functionality for creating a new presentation
    $scope.showCreateForm = function () {
        $scope.creating = true;
    };

    $scope.closeCreateForm = function () {
        $scope.creating = false;
        refreshPresentationObj();
    };

    function refreshPresentationObj () {   // refresh $scope.newPresentation object
        $scope.newPresentation = {
            title: '',
            presenter: null,
            media: []
        };
    }

    $scope.newPresentation = {
        title: '',
        presenter: null,
        media: []
    };

    // creating a presentation also adds the user as a presenter to a particular conference
    // creating a presentation merely adds it to the db; it does not initally contain media
    $scope.createPresentation = function (conference_id) {
        $scope.creating = false;    // to hide the input box
        return PresentationFactory.createPresentation($scope.newPresentation)
                .then(function (newPresentation) {
                    $scope.presentations.push(newPresentation);
                    refreshPresentationObj();
                    return ConferenceFactory.addConferencePresenter(conference_id, Session.user._id);
                })
                .then(function (conference) {
                    console.log('added the user to this conference as a presenter: ', conference);
                    // should something else happen here on the ui?
                });
    };

    // functionality for removing a presentation goes here
    $scope.checkboxModel = {};   // tracks all the checkboxes

    $scope.deletePresentations = function () {
        var idsToDelete = [], deleted_ids = [];
        angular.forEach($scope.checkboxModel, function(value, checkbox_id) {
            if (value === true) {         // i.e. checkbox is checked
                this.push(checkbox_id);      // push in checkbox_id which is the presentation id
            }
        }, idsToDelete);
        PresentationFactory.deletePresentations(idsToDelete)
        .then(function (deletedPromises) {
                angular.forEach(deletedPromises, function (response) {
                    deleted_ids.push(response.data._id);
                });
            $scope.presentations = _.remove($scope.presentations, function (item) {
                return deleted_ids.indexOf(item._id) == -1;
            });
            $scope.checkboxModel = _.omit($scope.checkboxModel, deleted_ids);
        });
        // should the function also check for the relevant conference and delete the user from the presenters array?
        // Wesley says - "no"
    };
});<|endoftext|>