<commit_before>'use strict';

module.exports = function ( InternalObject ) {

	var ExternalObject = function () {

		var initiatedObject = new InternalObject( arguments );

		// Add internal
		Object.defineProperty( InternalObject.prototype, 'private', {
			'enumerable' : false,
			'value'      : {}
		} );

		// Add public methods to InternalObject
		for ( var property in this ) {

			if ( typeof ExternalObject.prototype[ property ] === 'function' ) {
				InternalObject.prototype[ property ] = ExternalObject.prototype[ property ].bind( initiatedObject );

			} else {
				InternalObject.prototype[ property ] = ExternalObject.prototype[ property ];
			}
		}

		// Add private methods to InternalObject
		for ( var property in this.private ) {

			if ( typeof ExternalObject.prototype.private[ property ] === 'function' ) {
				InternalObject.prototype.private[ property ] = ExternalObject.prototype.private[ property ].bind( initiatedObject );

			} else {
				InternalObject.prototype.private[ property ] = ExternalObject.prototype.private[ property ];
			}
		}

		// Remap ExternalObject to initiatedObject
		for ( var property in this ) {

			if ( typeof initiatedObject[ property ] === 'function' ) {
				this[ property ] = initiatedObject[ property ].bind( initiatedObject );

			} else {
				this[ property ] = initiatedObject[ property ];
			}
		}

		// Delete ExternalObject .private attribute
		Object.defineProperty( this, 'private', {
			'enumerable' : false,
			'value'      : undefined
		} );
	};

	// Add ExternalObject .private attribute
	Object.defineProperty( ExternalObject.prototype, 'private', {
		'enumerable' : false,
		'value'      : {}
	} );

	// Add index for extending other classes
	ExternalObject.extends = function ( extendingClass ) {

		for ( var property in extendingClass.prototype ) {
			ExternalObject.prototype[ property ] = extendingClass.prototype[ property ];
		}

		for ( var property in extendingClass.prototype.private ) {
			ExternalObject.prototype.private[ property ] = extendingClass.prototype.private[ property ];
		}
	};

	return ExternalObject;
};
<commit_msg>Dcoumentation: title<commit_after>'use strict';

/* ====================================== *\
         Class Constructor Function
\* ====================================== */

module.exports = function ( InternalObject ) {

	var ExternalObject = function () {

		var initiatedObject = new InternalObject( arguments );

		// Add internal
		Object.defineProperty( InternalObject.prototype, 'private', {
			'enumerable' : false,
			'value'      : {}
		} );

		// Add public methods to InternalObject
		for ( var property in this ) {

			if ( typeof ExternalObject.prototype[ property ] === 'function' ) {
				InternalObject.prototype[ property ] = ExternalObject.prototype[ property ].bind( initiatedObject );

			} else {
				InternalObject.prototype[ property ] = ExternalObject.prototype[ property ];
			}
		}

		// Add private methods to InternalObject
		for ( var property in this.private ) {

			if ( typeof ExternalObject.prototype.private[ property ] === 'function' ) {
				InternalObject.prototype.private[ property ] = ExternalObject.prototype.private[ property ].bind( initiatedObject );

			} else {
				InternalObject.prototype.private[ property ] = ExternalObject.prototype.private[ property ];
			}
		}

		// Remap ExternalObject to initiatedObject
		for ( var property in this ) {

			if ( typeof initiatedObject[ property ] === 'function' ) {
				this[ property ] = initiatedObject[ property ].bind( initiatedObject );

			} else {
				this[ property ] = initiatedObject[ property ];
			}
		}

		// Delete ExternalObject .private attribute
		Object.defineProperty( this, 'private', {
			'enumerable' : false,
			'value'      : undefined
		} );
	};

	// Add ExternalObject .private attribute
	Object.defineProperty( ExternalObject.prototype, 'private', {
		'enumerable' : false,
		'value'      : {}
	} );

	// Add index for extending other classes
	ExternalObject.extends = function ( extendingClass ) {

		for ( var property in extendingClass.prototype ) {
			ExternalObject.prototype[ property ] = extendingClass.prototype[ property ];
		}

		for ( var property in extendingClass.prototype.private ) {
			ExternalObject.prototype.private[ property ] = extendingClass.prototype.private[ property ];
		}
	};

	return ExternalObject;
};
<|endoftext|>


<commit_before>/* global math */
/* eslint-disable no-unused-vars */
var utils = {
  strWrap: (str) => {
    if (str.includes('\n') || (str.includes('"') && str.includes("'"))) return '`';
    return !str.includes("'") ? "'" : '"';
  },

  escapeRegExp: (str, q) => str.replace(new RegExp(`[\\\\${q}\\n]`, 'g'), '\\$&').replace(/-/g, '\\x2d'),

  _unescape: (str) => {
    for (let i = 32; i < 128; i++) {
      str = str.replace(new RegExp('\\\\x' + i.toString(16), 'ig'), String.fromCharCode(i));
    }
    str = str.replace(/\\x09/g, '\t');
    return str;
  },

  strMerge: (str) => str.replace(/'\s*\+\s*'|"\s*\+\s*"/g, ''),

  methodChain: (str) => str.replace(/(?<!\()\[("|')((?!\d)[a-z_\d$]*)("|')\]/gi, '.$2 '),

  calcHex: (str) => {
    str = str.replace(/(?<!['"])(?<!\w)0x[a-f\d]+((?<!\w)0x[a-f\d]+|[+\-*/])*(?<!\w)0x[a-f\d]+(?!['"])/gi, (m) =>
      math.format(eval(m), 14),
    );
    str = str.replace(/(?<!['"])(?<!\w)0x[a-f\d]+(?!['"])/gi, (m) => eval(m));
    return str;
  },

  calcNumber: (str) => {
    str = str.replace(/\(([\d.]+)\)/g, '$1');
    str = str.replace(/(?<!['"\w])\d[+\-*/\d.]*\d(?!['"\w])/g, (m) => {
      if (!/[+\-*/]/.test(m)) return m;
      return math.format(math.evaluate(m), 14);
    });
    return str;
  },

  _boolean: (str) =>
    str.replace(/((?<=([=:(,|&[]|return|=>))|^)!{1,2}(\[\]|0|1)((?=[;,)}|&\]])|$)/g, (m) => eval(m).toString()),

  propArr: (str) => str.replace(/\[\((['"])((?!\d)[a-z_\d$]*)['"]\)\]/gi, '[$1$2$1]'),
};
<commit_msg>Update methodChain<commit_after>/* global math */
/* eslint-disable no-unused-vars */
var utils = {
  strWrap: (str) => {
    if (str.includes('\n') || (str.includes('"') && str.includes("'"))) return '`';
    return !str.includes("'") ? "'" : '"';
  },

  escapeRegExp: (str, q) => str.replace(new RegExp(`[\\\\${q}\\n]`, 'g'), '\\$&').replace(/-/g, '\\x2d'),

  _unescape: (str) => {
    for (let i = 32; i < 128; i++) {
      str = str.replace(new RegExp('\\\\x' + i.toString(16), 'ig'), String.fromCharCode(i));
    }
    str = str.replace(/\\x09/g, '\t');
    return str;
  },

  strMerge: (str) => str.replace(/'\s*\+\s*'|"\s*\+\s*"/g, ''),

  methodChain: (str) => str.replace(/(?<=[a-z_\d$\])])\[("|')((?!\d)[a-z_\d$]*)("|')\]/gi, '.$2 '),

  calcHex: (str) => {
    str = str.replace(/(?<!['"])(?<!\w)0x[a-f\d]+((?<!\w)0x[a-f\d]+|[+\-*/])*(?<!\w)0x[a-f\d]+(?!['"])/gi, (m) =>
      math.format(eval(m), 14),
    );
    str = str.replace(/(?<!['"])(?<!\w)0x[a-f\d]+(?!['"])/gi, (m) => eval(m));
    return str;
  },

  calcNumber: (str) => {
    str = str.replace(/\(([\d.]+)\)/g, '$1');
    str = str.replace(/(?<!['"\w])\d[+\-*/\d.]*\d(?!['"\w])/g, (m) => {
      if (!/[+\-*/]/.test(m)) return m;
      return math.format(math.evaluate(m), 14);
    });
    return str;
  },

  _boolean: (str) =>
    str.replace(/((?<=([=:(,|&[]|return|=>))|^)!{1,2}(\[\]|0|1)((?=[;,)}|&\]])|$)/g, (m) => eval(m).toString()),

  propArr: (str) => str.replace(/\[\((['"])((?!\d)[a-z_\d$]*)['"]\)\]/gi, '[$1$2$1]'),
};
<|endoftext|>


<commit_before>function mobile() {
    alert("Please rotate your phone to landscape view for a better display! Also please click on photos for descriptions or external links.");
}

jQuery(document).ready(function($) {

	$(".main-menu a").click(function(){
		var id =  $(this).attr('class');
		id = id.split('-');
		$('a.active').removeClass('active');
    	$(this).addClass('active');
		$("#menu-container .content").slideUp('slow');
		$("#menu-container #menu-"+id[1]).slideDown('slow');
		$("#menu-container .homepage").slideUp('slow');
		return false;
	});

	$(".main-menu a.homebutton").click(function(){
		$("#menu-container .content").slideUp('slow');
		$("#menu-container .homepage").slideDown('slow');
		return false;
	});

	$(".main-menu a.aboutbutton").click(function(){
		$("#menu-container .content").slideUp('slow');
		$("#menu-container .about-section").slideDown('slow');
		return false;
	});

	$(".main-menu a.projectbutton").click(function(){
		$("#menu-container .content").slideUp('slow');
		$("#menu-container .project-section").slideDown('slow');
		return false;
	});

	$(".main-menu a.blogbutton").click(function(){
		$("#menu-container .content").slideUp('slow');
		$("#menu-container .blog-section").slideDown('slow');
		return false;
	});

	$(".main-menu a.contactbutton").click(function(){
		$("#menu-container .content").fadeOut();
		$("#menu-container .contact-section").slideDown('slow');
		loadScript();
		return false;
	});

	$('a.toggle-nav').click(function(){
		$('.menu-responsive').slideToggle();
	});

	$('.menu-responsive a').click(function() {
		$('.menu-responsive').slideToggle().hide();
	});

  	$("#hide").click(function(){
    	$(".pwm").hide(500);
  	});
  	$("#show").click(function(){
    	$(".pwm").show(500);
  	});

});

function targetopener(mylink, closeme, closeonly) {
	if (! (window.focus&& window.opener))return true;
	window.opener.focus();
	if (! closeonly)window.opener.location.href=mylink.href;
	if (closeme)window.close();
	return false;
}

function loadScript() {
	  var script = document.createElement('script');
	  script.type = 'text/javascript';
	  script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&' +
	      'callback=initialize';
	  document.body.appendChild(script);
	}

	function initialize() {
	    var mapOptions = {
	      zoom: 15,
	      center: new google.maps.LatLng(51.524516,-0.133809)
	    };
	    var map = new google.maps.Map(document.getElementById('map_canvas'),  mapOptions);
	}<commit_msg>js edit<commit_after>function mobile() {
    alert("Please rotate your phone to landscape view for a better display!");
}

jQuery(document).ready(function($) {

	$(".main-menu a").click(function(){
		var id =  $(this).attr('class');
		id = id.split('-');
		$('a.active').removeClass('active');
    	$(this).addClass('active');
		$("#menu-container .content").slideUp('slow');
		$("#menu-container #menu-"+id[1]).slideDown('slow');
		$("#menu-container .homepage").slideUp('slow');
		return false;
	});

	$(".main-menu a.homebutton").click(function(){
		$("#menu-container .content").slideUp('slow');
		$("#menu-container .homepage").slideDown('slow');
		return false;
	});

	$(".main-menu a.aboutbutton").click(function(){
		$("#menu-container .content").slideUp('slow');
		$("#menu-container .about-section").slideDown('slow');
		return false;
	});

	$(".main-menu a.projectbutton").click(function(){
		$("#menu-container .content").slideUp('slow');
		$("#menu-container .project-section").slideDown('slow');
		return false;
	});

	$(".main-menu a.blogbutton").click(function(){
		$("#menu-container .content").slideUp('slow');
		$("#menu-container .blog-section").slideDown('slow');
		return false;
	});

	$(".main-menu a.contactbutton").click(function(){
		$("#menu-container .content").fadeOut();
		$("#menu-container .contact-section").slideDown('slow');
		loadScript();
		return false;
	});

	$('a.toggle-nav').click(function(){
		$('.menu-responsive').slideToggle();
	});

	$('.menu-responsive a').click(function() {
		$('.menu-responsive').slideToggle().hide();
	});

  	$("#hide").click(function(){
    	$(".pwm").hide(500);
  	});
  	$("#show").click(function(){
    	$(".pwm").show(500);
  	});

});

function targetopener(mylink, closeme, closeonly) {
	if (! (window.focus&& window.opener))return true;
	window.opener.focus();
	if (! closeonly)window.opener.location.href=mylink.href;
	if (closeme)window.close();
	return false;
}

function loadScript() {
	  var script = document.createElement('script');
	  script.type = 'text/javascript';
	  script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&' +
	      'callback=initialize';
	  document.body.appendChild(script);
	}

	function initialize() {
	    var mapOptions = {
	      zoom: 15,
	      center: new google.maps.LatLng(51.524516,-0.133809)
	    };
	    var map = new google.maps.Map(document.getElementById('map_canvas'),  mapOptions);
	}<|endoftext|>


<commit_before>//
// Copyright (C) 2014 - present Instructure, Inc.
//
// This file is part of Canvas.
//
// Canvas is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, version 3 of the License.
//
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.

import DialogManager from '../media_comments/dialog_manager'
import CommentUiLoader from '../media_comments/comment_ui_loader'
import K5Uploader from 'bower/k5uploader/k5uploader'
import UploadViewManager from '../media_comments/upload_view_manager'
import KalturaSessionLoader from '../media_comments/kaltura_session_loader'
import FileInputManager from '../media_comments/file_input_manager'

/*
   * Creates and Mediates between various upload ui and actors
   */
export default class JsUploader {
  constructor() {
    this.initialize = this.initialize.bind(this)
    this.doUpload = this.doUpload.bind(this)
    this.doUploadByFile = this.doUploadByFile.bind(this)
    this.onFileError = this.onFileError.bind(this)
    this.onUploadComplete = this.onUploadComplete.bind(this)
    this.onUploaderReady = this.onUploaderReady.bind(this)
    this.resetUploader = this.resetUploader.bind(this)
    this.dialogManager = new DialogManager()
    this.commentUiLoader = new CommentUiLoader()
    this.kSession = new KalturaSessionLoader()
    this.uploadViewManager = new UploadViewManager()
    this.fileInputManager = new FileInputManager()
    this.dialogManager.initialize()
    this.loadSession()
  }

  loadSession() {
    return this.kSession.loadSession(
      '/api/v1/services/kaltura_session',
      this.initialize,
      this.uploadViewManager.showConfigError
    )
  }

  onReady() {}
  // override this

  initialize(mediaType, opts) {
    return this.commentUiLoader.loadTabs(html => {
      this.onReady()
      this.dialogManager.displayContent(html)
      this.dialogManager.activateTabs()
      this.dialogManager.mediaReady(mediaType, opts)
      this.createNeededFields()
      return this.bindEvents()
    })
  }

  getKs() {
    return this.kSession.kalturaSession.ks
  }

  getUid() {
    return this.kSession.kalturaSession.uid
  }

  bindEvents() {
    this.fileInputManager.setUpInputTrigger('#audio_upload_holder', ['audio'])
    return this.fileInputManager.setUpInputTrigger('#video_upload_holder', ['video'])
  }

  createNeededFields() {
    return this.fileInputManager.resetFileInput(this.doUpload)
  }

  doUpload() {
    this.file = this.fileInputManager.getSelectedFile()
    if (this.uploader) this.resetUploader()
    const session = this.kSession.generateUploadOptions(this.fileInputManager.allowedMedia)
    this.uploader = new K5Uploader(session)
    this.uploader.addEventListener('K5.fileError', this.onFileError)
    this.uploader.addEventListener('K5.complete', this.onUploadComplete)
    this.uploader.addEventListener('K5.ready', this.onUploaderReady)

    this.uploadViewManager = new UploadViewManager()
    return this.uploadViewManager.monitorUpload(
      this.uploader,
      this.fileInputManager.allowedMedia,
      this.file
    )
  }

  doUploadByFile(inputFile) {
    this.file = inputFile
    if (this.uploader) {
      this.resetUploader()
    }
    const session = this.kSession.generateUploadOptions(['video', 'audio', 'webm', 'video/webm', 'audio/webm'])
    this.uploader = new K5Uploader(session)
    this.uploader.addEventListener('K5.fileError', this.onFileError)
    this.uploader.addEventListener('K5.complete', this.onUploadCompleteFileType(this.file.type === "audio/webm" ))
    return this.uploader.addEventListener('K5.ready', this.onUploaderReady)
  }

  onFileError() {
    return this.createNeededFields()
  }

  onUploadCompleteFileType (isAudioFileType) {
    return (e) => this.onUploadComplete(e, isAudioFileType);
  }

  onUploadComplete(e, isAudioFileComplete) {
    this.resetUploader()
    if (!((e.title != null ? e.title.length : undefined) > 0)) {
      e.title = this.file.name
    }
    this.addEntry(e, isAudioFileComplete)
    return this.dialogManager.hide()
  }

  onUploaderReady() {
    return this.uploader.uploadFile(this.file)
  }

  resetUploader() {
    this.uploader.removeEventListener('K5.fileError', this.onFileError)
    this.uploader.removeEventListener('K5.complete', this.onUploadComplete)
    this.uploader.removeEventListener('K5.ready', this.onUploaderReady)
    return this.uploader.destroy()
  }
}
<commit_msg>fix audio only upload files display<commit_after>//
// Copyright (C) 2014 - present Instructure, Inc.
//
// This file is part of Canvas.
//
// Canvas is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, version 3 of the License.
//
// Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.

import DialogManager from '../media_comments/dialog_manager'
import CommentUiLoader from '../media_comments/comment_ui_loader'
import K5Uploader from 'bower/k5uploader/k5uploader'
import UploadViewManager from '../media_comments/upload_view_manager'
import KalturaSessionLoader from '../media_comments/kaltura_session_loader'
import FileInputManager from '../media_comments/file_input_manager'

/*
   * Creates and Mediates between various upload ui and actors
   */
export default class JsUploader {
  constructor() {
    this.initialize = this.initialize.bind(this)
    this.doUpload = this.doUpload.bind(this)
    this.doUploadByFile = this.doUploadByFile.bind(this)
    this.onFileError = this.onFileError.bind(this)
    this.onUploadComplete = this.onUploadComplete.bind(this)
    this.onUploaderReady = this.onUploaderReady.bind(this)
    this.resetUploader = this.resetUploader.bind(this)
    this.dialogManager = new DialogManager()
    this.commentUiLoader = new CommentUiLoader()
    this.kSession = new KalturaSessionLoader()
    this.uploadViewManager = new UploadViewManager()
    this.fileInputManager = new FileInputManager()
    this.dialogManager.initialize()
    this.loadSession()
  }

  loadSession() {
    return this.kSession.loadSession(
      '/api/v1/services/kaltura_session',
      this.initialize,
      this.uploadViewManager.showConfigError
    )
  }

  onReady() {}
  // override this

  initialize(mediaType, opts) {
    return this.commentUiLoader.loadTabs(html => {
      this.onReady()
      this.dialogManager.displayContent(html)
      this.dialogManager.activateTabs()
      this.dialogManager.mediaReady(mediaType, opts)
      this.createNeededFields()
      return this.bindEvents()
    })
  }

  getKs() {
    return this.kSession.kalturaSession.ks
  }

  getUid() {
    return this.kSession.kalturaSession.uid
  }

  bindEvents() {
    this.fileInputManager.setUpInputTrigger('#audio_upload_holder', ['audio'])
    return this.fileInputManager.setUpInputTrigger('#video_upload_holder', ['video'])
  }

  createNeededFields() {
    return this.fileInputManager.resetFileInput(this.doUpload)
  }

  doUpload() {
    this.file = this.fileInputManager.getSelectedFile()
    if (this.uploader) this.resetUploader()
    const session = this.kSession.generateUploadOptions(this.fileInputManager.allowedMedia)
    this.uploader = new K5Uploader(session)
    this.uploader.addEventListener('K5.fileError', this.onFileError)
    this.uploader.addEventListener('K5.complete', this.onUploadComplete)
    this.uploader.addEventListener('K5.ready', this.onUploaderReady)

    this.uploadViewManager = new UploadViewManager()
    return this.uploadViewManager.monitorUpload(
      this.uploader,
      this.fileInputManager.allowedMedia,
      this.file
    )
  }

  doUploadByFile(inputFile) {
    this.file = inputFile
    if (this.uploader) {
      this.resetUploader()
    }
    const session = this.kSession.generateUploadOptions(['video', 'audio', 'webm', 'video/webm', 'audio/webm'])
    this.uploader = new K5Uploader(session)
    this.uploader.addEventListener('K5.fileError', this.onFileError)
    this.uploader.addEventListener('K5.complete', this.onUploadComplete)
    return this.uploader.addEventListener('K5.ready', this.onUploaderReady)
  }

  onFileError() {
    return this.createNeededFields()
  }

  onUploadComplete(e) {
    this.resetUploader()
    if (!((e.title != null ? e.title.length : undefined) > 0)) {
      e.title = this.file.name
    }
    this.addEntry(e, this.file.type.includes("audio"))
    return this.dialogManager.hide()
  }

  onUploaderReady() {
    return this.uploader.uploadFile(this.file)
  }

  resetUploader() {
    this.uploader.removeEventListener('K5.fileError', this.onFileError)
    this.uploader.removeEventListener('K5.complete', this.onUploadComplete)
    this.uploader.removeEventListener('K5.ready', this.onUploaderReady)
    return this.uploader.destroy()
  }
}
<|endoftext|>


<commit_before>/**
 * (c) 2016 Tieto Finland Oy
 * Licensed under the MIT license.
 */
'use strict';

/**
 * @ngdoc directive
 * @name dashboard.proposals:proposalsDirective
 * @description
 * # proposalsDirective
 */
angular.module('dashboard')
    .constant('PROPS', {
        'PUBLISHED': {
            NO: 0,
            YES: 1
        },
        'TYPE': [
            { value: 1, text: "Päätös" },
            { value: 2, text: "Esityksen muutos" },
            { value: 3, text: "Pöydällepanoehdotus" },
            { value: 4, text: "Palautusehdotus" },
            { value: 5, text: "Vastaehdotus" },
            { value: 6, text: "Hylkäysehdotus" },
            { value: 7, text: "Ponsi" },
            { value: 8, text: "Eriävä mielipide" },
            { value: 9, text: "Esteellinen" },
            { value: 10, text: "Esityksen poisto" }
        ],
        'TOGGLE': 'PROPS.TOGGLE'
    })
    .directive('dbProposals', [function() {

        var controller = ['$log', '$scope', 'AhjoProposalsSrv', 'PROPS', '$rootScope', function($log, $scope, AhjoProposalsSrv, PROPS, $rootScope) {
            $log.log("dbProposals: CONTROLLER");
            var self = this;
            self.proposals = null;
            self.tps = PROPS.TYPE;
            self.published = PROPS.PUBLISHED;
            self.isMobile = $rootScope.isMobile;
            self.isAllOpen = false;

            function getProposals(guid) {
                if (typeof guid === 'string') {
                    var getResult = null;

                    AhjoProposalsSrv.get({ 'guid': guid }).$promise.then(function(response) {
                        $log.debug("dbProposals: get then: ");
                        getResult = response.objects;
                    }, function(error) {
                        $log.error("dbProposals: get error: " + JSON.stringify(error));
                    }, function(notify) {
                        $log.debug("dbProposals: get notify: " + JSON.stringify(notify));
                    }).finally(function() {
                        $log.debug("dbProposals: get finally: ");
                        if (getResult instanceof Object) {
                            self.proposals = angular.copy(getResult);
                        }
                    });
                }
                else {
                    $log.error('dbProposals: getProposals parameter invalid');
                }
            }

            function postProposal(proposal) {
                if (proposal instanceof Object) {
                    var postResult = null;

                    if (proposal.isNew) {
                        delete proposal.isNew;
                    }

                    AhjoProposalsSrv.post(proposal).$promise.then(function(response) {
                        $log.debug("dbProposals: post then: " + JSON.stringify(response));
                        postResult = (response instanceof Object) ? response.Data : null;
                    }, function(error) {
                        $log.error("dbProposals: post error: " + JSON.stringify(error));
                    }, function(notify) {
                        $log.debug("dbProposals: post notify: " + JSON.stringify(notify));
                    }).finally(function() {
                        $log.debug("dbProposals: post finally: ");
                        if (postResult instanceof Object) {
                            $log.debug(JSON.stringify(postResult.Message));
                        }
                    });
                }
                else {
                    $log.error('dbProposals: postProposal parameter invalid');
                }
            }

            function deleteProposal(proposal) {
                if (proposal instanceof Object) {
                    if (proposal.isNew && self.proposals instanceof Array) {
                        for (var index = 0; index < self.proposals.length; index++) {
                            if (angular.equals(proposal, self.proposals[index])) {
                                self.proposals.splice(index, 1);
                            }
                        }
                    }
                    else {
                        if (proposal instanceof Object) {
                            AhjoProposalsSrv.delete(proposal).$promise.then(function(response) {
                                $log.debug("dbProposals: delete then: " + JSON.stringify(response));
                            }, function(error) {
                                $log.error("dbProposals: delete error: " + JSON.stringify(error));
                            }, function(notify) {
                                $log.debug("dbProposals: delete notify: " + JSON.stringify(notify));
                            }).finally(function() {
                                $log.debug("dbProposals: delete finally: ");
                            });
                        }
                        else {
                            $log.error('dbProposals: deleteProposal parameter invalid');
                        }
                    }
                }
            }

            function createDraft(item) {
                return {
                    "personGuid": "926eee0b-8e94-4a14-beec-d9b60590547f",
                    "proposalGuid": "",
                    "firstName": "",
                    "lastName": "",
                    "personName": "",
                    "topicGuid": $scope.guid,
                    "text": "",
                    "proposalType": item.value,
                    "remarkDescription": "",
                    "isPublished": 0,
                    "isTranslatedIcon": "",
                    "isPublishedIcon": "",
                    "translated": "",
                    "language": "fi",
                    "insertDateTime": "",
                    "orderNumber": "",
                    "translationText": "",
                    "translationTaskGuid": "",
                    "translationTime": "",
                    "isMinuteEntryBase": "",
                    "isModified": "",
                    "isCopy": "",
                    "isNew": true
                };
            }

            self.post = function(proposal) {
                postProposal(proposal);
            };

            self.delete = function(proposal) {
                deleteProposal(proposal);
            };

            self.addProposal = function(item) {
                if ((self.proposals instanceof Array) === false) {
                    self.proposals = [];
                }
                self.proposals.splice(0, 0, createDraft(item));
            };

            self.toggleAll = function() {
                self.isAllOpen = !self.isAllOpen;
                $rootScope.$emit(PROPS.TOGGLE, self.isAllOpen);
            };

            $scope.$watch(function() {
                return {
                    guid: $scope.guid
                };
            }, function(data) {
                getProposals(data.guid);
            }, true);

            $scope.$on('$destroy', function() {
                $log.debug("dbProposals: DESTROY");
            });

            getProposals($scope.guid);

        }];

        return {
            scope: {
                guid: '='
            },
            templateUrl: 'directives/proposals/proposals.Directive.html',
            restrict: 'AE',
            controller: controller,
            controllerAs: 'c',
            replace: 'true'
        };
    }]);
<commit_msg>delete proposal implemented<commit_after>/**
 * (c) 2016 Tieto Finland Oy
 * Licensed under the MIT license.
 */
'use strict';

/**
 * @ngdoc directive
 * @name dashboard.proposals:proposalsDirective
 * @description
 * # proposalsDirective
 */
angular.module('dashboard')
    .constant('PROPS', {
        'PUBLISHED': {
            NO: 0,
            YES: 1
        },
        'TYPE': [
            { value: 1, text: "Päätös" },
            { value: 2, text: "Esityksen muutos" },
            { value: 3, text: "Pöydällepanoehdotus" },
            { value: 4, text: "Palautusehdotus" },
            { value: 5, text: "Vastaehdotus" },
            { value: 6, text: "Hylkäysehdotus" },
            { value: 7, text: "Ponsi" },
            { value: 8, text: "Eriävä mielipide" },
            { value: 9, text: "Esteellinen" },
            { value: 10, text: "Esityksen poisto" }
        ],
        'TOGGLE': 'PROPS.TOGGLE'
    })
    .directive('dbProposals', [function() {

        var controller = ['$log', '$scope', 'AhjoProposalsSrv', 'PROPS', '$rootScope', function($log, $scope, AhjoProposalsSrv, PROPS, $rootScope) {
            $log.log("dbProposals: CONTROLLER");
            var self = this;
            self.proposals = null;
            self.tps = PROPS.TYPE;
            self.published = PROPS.PUBLISHED;
            self.isMobile = $rootScope.isMobile;
            self.isAllOpen = false;

            function removeProposal(proposal) {
                if (proposal instanceof Object) {
                    for (var index = 0; index < self.proposals.length; index++) {
                        if (angular.equals(proposal, self.proposals[index])) {
                            self.proposals.splice(index, 1);
                        }
                    }
                }
            }

            function getProposals(guid) {
                if (typeof guid === 'string') {
                    var getResult = null;

                    AhjoProposalsSrv.get({ 'guid': guid }).$promise.then(function(response) {
                        $log.debug("dbProposals: get then: ");
                        getResult = response.objects;
                    }, function(error) {
                        $log.error("dbProposals: get error: " + JSON.stringify(error));
                    }, function(notify) {
                        $log.debug("dbProposals: get notify: " + JSON.stringify(notify));
                    }).finally(function() {
                        $log.debug("dbProposals: get finally: ");
                        if (getResult instanceof Object) {
                            self.proposals = angular.copy(getResult);
                        }
                    });
                }
                else {
                    $log.error('dbProposals: getProposals parameter invalid');
                }
            }

            function postProposal(proposal) {
                if (proposal instanceof Object) {
                    var postResult = null;

                    if (proposal.isNew) {
                        delete proposal.isNew;
                    }

                    AhjoProposalsSrv.post(proposal).$promise.then(function(response) {
                        $log.debug("dbProposals: post then: " + JSON.stringify(response));
                        postResult = (response instanceof Object) ? response.Data : null;
                    }, function(error) {
                        $log.error("dbProposals: post error: " + JSON.stringify(error));
                    }, function(notify) {
                        $log.debug("dbProposals: post notify: " + JSON.stringify(notify));
                    }).finally(function() {
                        $log.debug("dbProposals: post finally: ");
                        if (postResult instanceof Object) {
                            $log.debug(JSON.stringify(postResult.Message));
                        }
                    });
                }
                else {
                    $log.error('dbProposals: postProposal parameter invalid');
                }
            }

            function deleteProposal(proposal) {
                if (proposal instanceof Object) {
                    if (proposal.isNew && self.proposals instanceof Array) {
                        removeProposal(proposal);
                    }
                    else {
                        AhjoProposalsSrv.delete(proposal).$promise.then(function(response) {
                            $log.debug("dbProposals: delete then: " + JSON.stringify(response));
                            removeProposal(proposal);
                        }, function(error) {
                            $log.error("dbProposals: delete error: " + JSON.stringify(error));
                        }, function(notify) {
                            $log.debug("dbProposals: delete notify: " + JSON.stringify(notify));
                        }).finally(function() {
                            $log.debug("dbProposals: delete finally: " + proposal.proposalGuid);
                        });
                    }
                }
                else {
                    $log.error('dbProposals: deleteProposal parameter invalid');
                }
            }

            function createDraft(item) {
                return {
                    "personGuid": "926eee0b-8e94-4a14-beec-d9b60590547f",
                    "proposalGuid": "",
                    "firstName": "",
                    "lastName": "",
                    "personName": "",
                    "topicGuid": $scope.guid,
                    "text": "",
                    "proposalType": item.value,
                    "remarkDescription": "",
                    "isPublished": 0,
                    "isTranslatedIcon": "",
                    "isPublishedIcon": "",
                    "translated": "",
                    "language": "fi",
                    "insertDateTime": "",
                    "orderNumber": "",
                    "translationText": "",
                    "translationTaskGuid": "",
                    "translationTime": "",
                    "isMinuteEntryBase": "",
                    "isModified": "",
                    "isCopy": "",
                    "isNew": true
                };
            }

            self.post = function(proposal) {
                postProposal(proposal);
            };

            self.delete = function(proposal) {
                deleteProposal(proposal);
            };

            self.addProposal = function(item) {
                if ((self.proposals instanceof Array) === false) {
                    self.proposals = [];
                }
                self.proposals.splice(0, 0, createDraft(item));
            };

            self.toggleAll = function() {
                self.isAllOpen = !self.isAllOpen;
                $rootScope.$emit(PROPS.TOGGLE, self.isAllOpen);
            };

            $scope.$watch(function() {
                return {
                    guid: $scope.guid
                };
            }, function(data) {
                getProposals(data.guid);
            }, true);

            $scope.$on('$destroy', function() {
                $log.debug("dbProposals: DESTROY");
            });

            getProposals($scope.guid);

        }];

        return {
            scope: {
                guid: '='
            },
            templateUrl: 'directives/proposals/proposals.Directive.html',
            restrict: 'AE',
            controller: controller,
            controllerAs: 'c',
            replace: 'true'
        };
    }]);
<|endoftext|>


<commit_before>import { Template } from 'meteor/templating';
import { ReactiveDict } from 'meteor/reactive-dict';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { _ } from 'meteor/underscore';
import { Recipes } from '/imports/api/recipe/RecipeCollection';
import { Tags } from '/imports/api/tag/TagCollection';
import { Images } from '/imports/api/image/ImageCollection';

const displaySuccessMessage = 'displaySuccessMessage';
const displayErrorMessages = 'displayErrorMessages';

Template.View_Recipe_Page.onCreated(function onCreated() {
  this.subscribe(Recipes.getPublicationName());
  this.subscribe(Tags.getPublicationName());
  this.subscribe(Images.getPublicationName());
  this.messageFlags = new ReactiveDict();
  this.messageFlags.set(displaySuccessMessage, false);
  this.messageFlags.set(displayErrorMessages, false);
  this.context = Recipes.getSchema().namedContext('View_Recipe_Page');

});

Template.View_Recipe_Page.helpers({
  successClass() {
    return Template.instance().messageFlags.get(displaySuccessMessage) ? 'success' : '';
  },
  displaySuccessMessage() {
    return Template.instance().messageFlags.get(displaySuccessMessage);
  },
  errorClass() {
    return Template.instance().messageFlags.get(displayErrorMessages) ? 'error' : '';
  },
  fieldError(fieldName) {
    const invalidKeys = Template.instance().context.invalidKeys();
    const errorObject = _.find(invalidKeys, (keyObj) => keyObj.name === fieldName);
    return errorObject && Template.instance().context.keyErrorMessage(errorObject.name);
  },
  recipe() {
    return Recipes.findDocWithRecipeID(FlowRouter.getParam('_id'));
  },

  recipeTags() {
    return _.where(Tags.find().fetch(), { recipeID: FlowRouter.getParam('_id') });
  },
  recipeImageURL(){
    console.log(Images.find().fetch())
    console.log(_.pluck(_.where(Images.find().fetch(), { recipeID: FlowRouter.getParam('_id') }), 'imageURL')[0] );
    return _.pluck(_.where(Images.find().fetch(), { recipeID: FlowRouter.getParam('_id') }), 'imageURL')[0];
  },

  costPerServing() {
    const recipe = Recipes.findDocWithRecipeID(FlowRouter.getParam('_id'));
    return (recipe.totalCost / recipe.noServings);
  },
  tagsNotInRecipe() {
    return _.filter(_.uniq(_.pluck(Tags.find().fetch(), 'tagName')), function (tagName) {
      return !_.contains(_.pluck(_.where(Tags.find().fetch(), { recipeID: FlowRouter.getParam('_id') }), 'tagName'), tagName)
        }
    ), function (tagName) {

      return { title: tagName };
    };
  },
});

Template.tagInput.onRendered(function () {
  this.$('.ui.search').search({
    source: _.map(
        _.filter(_.uniq(_.pluck(Tags.find().fetch(), 'tagName')), function (tagName) {
              return !_.contains(_.pluck(_.where(Tags.find().fetch(), { recipeID: FlowRouter.getParam('_id') }), 'tagName'), tagName)
            }
        ), function (tagName) {

          return { title: tagName };
        }
    ),
    error: false
  })
  ;

  this.$('.ui.search').search.settings.showNoResults = false;
});

Template.View_Recipe_Page.events({
  'submit .new-tag-form'(event, instance) {
    event.preventDefault();
    // Get tag name (text field)
    const tagName = event.target.text.value;
    // Get recipe ID
    const recipeID = FlowRouter.getParam('_id');
    const score = 1;

    const newTagData = { recipeID, tagName, score };

    // Clear out any old validation errors.
    // instance.context.resetValidation();
    // Invoke clean so that newContactData reflects what will be inserted.
    Tags.getSchema().clean(newTagData);
    // Determine validity.
    // instance.context.validate(newTagData);

    if (instance.context.isValid()) {
      const id = Tags.define(newTagData);

      instance.messageFlags.set(displayErrorMessages, false);
      instance.find('form').reset();
    } else {
      instance.messageFlags.set(displayErrorMessages, true);
    }
  },

});
<commit_msg>remove console log<commit_after>import { Template } from 'meteor/templating';
import { ReactiveDict } from 'meteor/reactive-dict';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { _ } from 'meteor/underscore';
import { Recipes } from '/imports/api/recipe/RecipeCollection';
import { Tags } from '/imports/api/tag/TagCollection';
import { Images } from '/imports/api/image/ImageCollection';

const displaySuccessMessage = 'displaySuccessMessage';
const displayErrorMessages = 'displayErrorMessages';

Template.View_Recipe_Page.onCreated(function onCreated() {
  this.subscribe(Recipes.getPublicationName());
  this.subscribe(Tags.getPublicationName());
  this.subscribe(Images.getPublicationName());
  this.messageFlags = new ReactiveDict();
  this.messageFlags.set(displaySuccessMessage, false);
  this.messageFlags.set(displayErrorMessages, false);
  this.context = Recipes.getSchema().namedContext('View_Recipe_Page');

});

Template.View_Recipe_Page.helpers({
  successClass() {
    return Template.instance().messageFlags.get(displaySuccessMessage) ? 'success' : '';
  },
  displaySuccessMessage() {
    return Template.instance().messageFlags.get(displaySuccessMessage);
  },
  errorClass() {
    return Template.instance().messageFlags.get(displayErrorMessages) ? 'error' : '';
  },
  fieldError(fieldName) {
    const invalidKeys = Template.instance().context.invalidKeys();
    const errorObject = _.find(invalidKeys, (keyObj) => keyObj.name === fieldName);
    return errorObject && Template.instance().context.keyErrorMessage(errorObject.name);
  },
  recipe() {
    return Recipes.findDocWithRecipeID(FlowRouter.getParam('_id'));
  },

  recipeTags() {
    return _.where(Tags.find().fetch(), { recipeID: FlowRouter.getParam('_id') });
  },
  recipeImageURL(){
    return _.pluck(_.where(Images.find().fetch(), { recipeID: FlowRouter.getParam('_id') }), 'imageURL')[0];
  },

  costPerServing() {
    const recipe = Recipes.findDocWithRecipeID(FlowRouter.getParam('_id'));
    return (recipe.totalCost / recipe.noServings);
  },
  tagsNotInRecipe() {
    return _.filter(_.uniq(_.pluck(Tags.find().fetch(), 'tagName')), function (tagName) {
      return !_.contains(_.pluck(_.where(Tags.find().fetch(), { recipeID: FlowRouter.getParam('_id') }), 'tagName'), tagName)
        }
    ), function (tagName) {

      return { title: tagName };
    };
  },
});

Template.tagInput.onRendered(function () {
  this.$('.ui.search').search({
    source: _.map(
        _.filter(_.uniq(_.pluck(Tags.find().fetch(), 'tagName')), function (tagName) {
              return !_.contains(_.pluck(_.where(Tags.find().fetch(), { recipeID: FlowRouter.getParam('_id') }), 'tagName'), tagName)
            }
        ), function (tagName) {

          return { title: tagName };
        }
    ),
    error: false
  })
  ;

  this.$('.ui.search').search.settings.showNoResults = false;
});

Template.View_Recipe_Page.events({
  'submit .new-tag-form'(event, instance) {
    event.preventDefault();
    // Get tag name (text field)
    const tagName = event.target.text.value;
    // Get recipe ID
    const recipeID = FlowRouter.getParam('_id');
    const score = 1;

    const newTagData = { recipeID, tagName, score };

    // Clear out any old validation errors.
    // instance.context.resetValidation();
    // Invoke clean so that newContactData reflects what will be inserted.
    Tags.getSchema().clean(newTagData);
    // Determine validity.
    // instance.context.validate(newTagData);

    if (instance.context.isValid()) {
      const id = Tags.define(newTagData);

      instance.messageFlags.set(displayErrorMessages, false);
      instance.find('form').reset();
    } else {
      instance.messageFlags.set(displayErrorMessages, true);
    }
  },

});
<|endoftext|>


<commit_before>/**
 * InputElementView
 * Controls the view of a single input element.
 */
var InputElementView = Backbone.View.extend({
  initialize: function (options) {
    _.bindAll(this, 'updateHandler', 'resetValue',
                    'beginStepDown', 'beginStepUp', 'toggleInfoBox');

    this.model       = this.options.model;
    this.element     = this.options.element;
    this.formatValue = this.__getFormatter();

    // Keeps track of intervals used to repeat stepDown and stepUp
    // operations when the user holds down the mouse button.
    this.incrementInterval = null;

    this.model.bind('change', this.updateHandler);

    var lSliderOptions = {
      'reset_value': this.model.get('start_value'),
      'value':       this.model.get('user_value'),
      'step_value':  this.model.get('step_value'),
      'min_value':   this.model.get('min_value'),
      'max_value':   this.model.get('max_value'),
      'name':        this.model.get('translated_name'),
      'share_group': this.model.get('share_group'),
      'disabled':    this.model.get('disabled'),
      'fixed':       this.model.get("input_element_type") == "fixed" ||
                     this.model.get("input_element_type") == "fixed_share",
      'formatter':   this.getFormatter(),
      'precision':   this.getPrecision(),
      'element':     this.element,
      'infoBox':     { 'disableDataBox': true }
    };

    this.sliderView = new AdvancedSliderView(lSliderOptions);

    this.set_full_label(this.model.get('label'));

    // make the toggle red if it's semi unadaptable and in a municipality.
    if (App.municipalityController.isMunicipality() &&
                this.model.get("semi_unadaptable")) {

      this.sliderView.slider.toggleButton.element.addClass('municipality-toggle');
    }

    this.render();
    this.initEventListeners();

    // Disable buttons?
    if (this.model.get('disabled')) {
      this.disableButton('reset');
      this.disableButton('decrease');
      this.disableButton('increase');
    }
  },

  /**
   * Creates the HTML elements used to display the slider.
   */
  render: function () {
    var quinnElement   = $('

'),
        wrapperElement = $('

'),

        // Need to keep hold of this to add the text to the new info box...
        description = this.element.find('.info-box .text').text(),

        quinnOnChange, quinnOnComplete;

    // TEMPLATING.

    // Start by removing the contents of the existing element, so that we
    // may add our own.
    this.element.empty();
    this.element.addClass('new-input-slider');

    // The label.
    wrapperElement.append(
      $('').text(this.model.get('translated_name')));

    // Reset and decrease-value buttons.
    this.resetElement = $('

');
    wrapperElement.append(this.resetElement);

    this.decreaseElement = $('

');
    wrapperElement.append(this.decreaseElement);

    // Holds the Quinn slider widget.
    wrapperElement.append(quinnElement);

    // Increase-value button.
    this.increaseElement = $('

');
    wrapperElement.append(this.increaseElement);

    // Displays the current value to the user.
    this.valueElement = $('

');
    wrapperElement.append(this.valueElement);

    // The help / info button.
    wrapperElement.append('

');

    // Finally, the help / info box itself.
    this.element.append(wrapperElement);
    this.element.append($('

').text(description));

    // INITIALIZATION.

    // The Quinn onChange event is fired whenever the user moves the slider
    // but not until the onComplete event is fired has the user _finished_.
    // onChange is for updating the UI only, onComplete is where persistance
    // should be. onChange is also fired once when the is initialized.
    quinnOnChange = _.bind(function (newValue, quinn) {
      this.setTransientValue(newValue, true);
    }, this);

    // Fired once the user has finished editing the value.
    quinnOnComplete = _.bind(function (newValue, quinn) {
      this.model.set({ user_value: newValue });
      this.checkMunicipalityNotice();
      this.trigger('change');
    }, this);

    // new $.Quinn is an alternative to $(...).quinn(), and allows us to
    // easily keep hold of the Quinn instance.
    this.quinn = new $.Quinn(quinnElement, {
      range:    [ this.model.get('min_value'),
                  this.model.get('max_value') ],

      value:      this.model.get('user_value'),
      step:       this.model.get('step_value'),
      disable:    this.model.get('disabled'),

      // Callbacks.
      onSetup:    quinnOnChange,
      onChange:   quinnOnChange,
      onComplete: quinnOnComplete
    });

    // EVENTS.

    this.element.
      delegate('.reset',     'click',     this.resetValue).
      delegate('.decrease',  'mousedown', this.beginStepDown).
      delegate('.increase',  'mousedown', this.beginStepUp).
      delegate('.show-info', 'click',     this.toggleInfoBox);

    return this;
  },

  /**
   * Disables a slider button.
   *
   * The sole argument should be the string "reset", "decrease", or "increase"
   * depending on which button you want to be disabled. All this does is add a
   * disabled class to the button, since the Quinn instance will enforce that
   * the value cannot be changed.
   */
  disableButton: function (buttonName) {
    var buttonElement = this[buttonName + 'Element'];
    buttonElement && buttonElement.addClass('disabled');
  },

  /**
   * Enables a slider button.
   *
   * The sole argument should be the string "reset", "decrease", or "increase"
   * depending on which button you want to be enabled.
   */
  enableButton: function (buttonName) {
    var buttonElement = this[buttonName + 'Element'];
    buttonElement && buttonElement.removeClass('disabled');
  },

  set_full_label: function (text) {
    this.element.find(".label").html(text);
  },

  /**
   * Init event listeners.
   */
  initEventListeners: function () {
    this.sliderView.slider.sliderVO.bind('update', $.proxy(function() {
      this.model.set({ 'user_value': this.sliderView.slider.getValue() });
    }, this));

    this.sliderView.getInfoBox().bind(
      'show', $.proxy(this.handleInputElementInfoBoxShowed, this));

    this.sliderView.bind(
      'change', $.proxy(this.checkMunicipalityNotice, this));

    this.sliderView.slider.bind(
      'change', $.proxy(this.handleSliderUpdate, this));
  },

  /**
   * Returns the number of decimal places used when formatting the value
   * shown for the input element.
   */
  getPrecision: function () {
    console.log('DEPRECATION: use formatValue instead of getPrecision');

    var lPrecisionStr = this.model.get('step_value').toString() + '';
    lPrecision = lPrecisionStr.replace('.', '').length - 1;
    return lPrecision;
  },

  /**
   * Returns a formatter on basis of the step_value.
   */
  getFormatter: function () {
    console.log('DEPRECATION: use formatValue instead of getFormatter');

    switch (this.model.get('unit')) {
      case "%":
        return SliderFormatter.numberWithSymbolFactory('%');
      case "#":
        return SliderFormatter.numberWithSymbolFactory('#');
      case "MW":
        return SliderFormatter.numberWithSymbolFactory('MW');
      case "km2":
        return SliderFormatter.numberWithSymbolFactory('km2');
      case "km":
        return SliderFormatter.numberWithSymbolFactory('km');
      case "x":
        return SliderFormatter.numberWithSymbolFactory('x');

      default:
        return null;
    }
  },

  /**
   * When the user does something on a slider this handler is invoked.
   */
  handleSliderUpdate: function () {
    this.disableUpdate = true;

    this.model.set({ 'user_value': this.quinn.value });

    this.sliderView.slider.setValue(
      this.model.get('user_value'), { noEvent: true });

    this.disableUpdate = false;
  },

  /**
   * This checks if the municipality message has been shown. It is has not
   * been shown, show it!
   */
  checkMunicipalityNotice:function () {
    if (this.model.get('semi_unadaptable') &&
          App.municipalityController.showMessage()) {

      App.municipalityController.showMunicipalityMessage();
    }
  },

  /**
   * Is called when something in the constraint model changed.
   * @override
   */
  updateHandler: function () {
    if (this.disableUpdate) {
      return;
    }

    this.sliderView.setValue(
      this.model.get('user_value'), { noEvent: true });

    return false;
  },

  /**
   * Is called when then infobox is clicked.
   * @override
   */
  handleInputElementInfoBoxShowed: function () {
    this.trigger('show');

    if (this.model.get('has_flash_movie')) {
      flowplayer('a.player', '/flash/flowplayer-3.2.6.swf');
    }
  },

  // ## Event Handlers

  /**
   * Updates elements of the UI to show the new slider value, but does _not_
   * set the value on the model (which is done later). The value is set on
   * the model as part of the Quinn onComplete callback (see `render`).
   *
   * The `fromSlider` argument indicates whether the new value has come from
   * the Quinn slider, in which case we can trust the value to fit the step,
   * min, and max values, and do not need to run the Quinn callbacks.
   *
   * TODO Buttons need may need to be enabled / disabled, such as when the new
   *      value is the minimum, the decrease button should not be clickable.
   */
  setTransientValue: function (newValue, fromSlider) {
    if (! fromSlider) {
      newValue = this.quinn.setValue(newValue);
    }

    this.valueElement.text(this.formatValue(newValue));

    return newValue;
  },

  /**
   * Resets the value of the slider to it's original value.
   */
  resetValue: function () {
    this.quinn.setValue(this.model.get('start_value'));
  },

  /**
   * Triggered when the users mouses-down on the decrease button. Reduces the
   * slider value by one step increment. If after HOLD_ACCELERATE ms the button
   * is still being held down, the slider value will continue to be decreased
   * until either the minimum value is reached, or the user lifts the button.
   */
  beginStepDown: function () {
    this.quinn.stepDown();
  },

  /**
   * Triggered when the users mouses-down on the increase button. Increases
   * the slider value by one step increment. If after HOLD_ACCELERATE ms the
   * button is still being held down, the slider value will continue to be
   * decreased until either the minimum value is reached, or the user lifts
   * the button.
   */
  beginStepUp: function () {
    this.quinn.stepUp();
  },

  /**
   * Toggles display of the slider information box.
   */
  toggleInfoBox: function () {
    this.element.toggleClass('info-box-visible');
  },

  // ## Pseudo-Private Methods

  /**
   * Used to format values in the .value div. Memoized as this.formatValue.
   */
  __getFormatter: function () {
    var mStep     = this.model.get('step_value'),
        mUnit     = this.model.get('unit'),
        unit      = '',
        precision = 0;

    if (_.isNumber(mStep)) {
        precision = mStep.toString().split('.');
        precision = precision[1] ? precision[1].length : 0
    }

    if (_.isString(mUnit)) {
      switch (mUnit) {
        case "%":
        case "#":
        case "MW":
        case "km2":
        case "km":
        case "x":
          unit = ' ' + mUnit;
          break;
        // Add custom units here...
      }
    }

    return function (value) {
      return value.toFixed(precision) + unit;
    };
  },
});

// The number of milliseconds which pass before stepping up and down values
// should begin being repeated.
InputElementView.HOLD_ACCELERATE = 125;
<commit_msg>Extract Quinn callbacks to separate methods.<commit_after>/**
 * InputElementView
 * Controls the view of a single input element.
 */
var InputElementView = Backbone.View.extend({
  initialize: function (options) {
    _.bindAll(this, 'updateHandler', 'resetValue', 'toggleInfoBox',
                    'beginStepDown', 'beginStepUp',
                    'quinnOnChange', 'quinnOnComplete');

    this.model       = this.options.model;
    this.element     = this.options.element;
    this.formatValue = this.__getFormatter();

    // Keeps track of intervals used to repeat stepDown and stepUp
    // operations when the user holds down the mouse button.
    this.incrementInterval = null;

    this.model.bind('change', this.updateHandler);

    var lSliderOptions = {
      'reset_value': this.model.get('start_value'),
      'value':       this.model.get('user_value'),
      'step_value':  this.model.get('step_value'),
      'min_value':   this.model.get('min_value'),
      'max_value':   this.model.get('max_value'),
      'name':        this.model.get('translated_name'),
      'share_group': this.model.get('share_group'),
      'disabled':    this.model.get('disabled'),
      'fixed':       this.model.get("input_element_type") == "fixed" ||
                     this.model.get("input_element_type") == "fixed_share",
      'formatter':   this.getFormatter(),
      'precision':   this.getPrecision(),
      'element':     this.element,
      'infoBox':     { 'disableDataBox': true }
    };

    this.sliderView = new AdvancedSliderView(lSliderOptions);

    this.set_full_label(this.model.get('label'));

    // make the toggle red if it's semi unadaptable and in a municipality.
    if (App.municipalityController.isMunicipality() &&
                this.model.get("semi_unadaptable")) {

      this.sliderView.slider.toggleButton.element.addClass('municipality-toggle');
    }

    this.render();
    this.initEventListeners();

    // Disable buttons?
    if (this.model.get('disabled')) {
      this.disableButton('reset');
      this.disableButton('decrease');
      this.disableButton('increase');
    }
  },

  /**
   * Creates the HTML elements used to display the slider.
   */
  render: function () {
    var quinnElement   = $('

'),
        wrapperElement = $('

'),

        // Need to keep hold of this to add the text to the new info box...
        description = this.element.find('.info-box .text').text(),

        quinnOnChange, quinnOnComplete;

    // TEMPLATING.

    // Start by removing the contents of the existing element, so that we
    // may add our own.
    this.element.empty();
    this.element.addClass('new-input-slider');

    // The label.
    wrapperElement.append(
      $('').text(this.model.get('translated_name')));

    // Reset and decrease-value buttons.
    this.resetElement = $('

');
    wrapperElement.append(this.resetElement);

    this.decreaseElement = $('

');
    wrapperElement.append(this.decreaseElement);

    // Holds the Quinn slider widget.
    wrapperElement.append(quinnElement);

    // Increase-value button.
    this.increaseElement = $('

');
    wrapperElement.append(this.increaseElement);

    // Displays the current value to the user.
    this.valueElement = $('

');
    wrapperElement.append(this.valueElement);

    // The help / info button.
    wrapperElement.append('

');

    // Finally, the help / info box itself.
    this.element.append(wrapperElement);
    this.element.append($('

').text(description));

    // INITIALIZATION.

    // new $.Quinn is an alternative to $(...).quinn(), and allows us to
    // easily keep hold of the Quinn instance.
    this.quinn = new $.Quinn(quinnElement, {
      range:    [ this.model.get('min_value'),
                  this.model.get('max_value') ],

      value:      this.model.get('user_value'),
      step:       this.model.get('step_value'),
      disable:    this.model.get('disabled'),

      // Callbacks.
      onChange:   this.quinnOnChange,
      onComplete: this.quinnOnComplete
    });

    // Need to do this manually, since setTransientValue needs this.quinn to
    // have been set.
    this.quinnOnChange(this.quinn.value, this.quinn);

    // EVENTS.

    this.element.
      delegate('.reset',     'click',     this.resetValue).
      delegate('.decrease',  'mousedown', this.beginStepDown).
      delegate('.increase',  'mousedown', this.beginStepUp).
      delegate('.show-info', 'click',     this.toggleInfoBox);

    return this;
  },

  /**
   * Disables a slider button.
   *
   * The sole argument should be the string "reset", "decrease", or "increase"
   * depending on which button you want to be disabled. All this does is add a
   * disabled class to the button, since the Quinn instance will enforce that
   * the value cannot be changed.
   */
  disableButton: function (buttonName) {
    var buttonElement = this[buttonName + 'Element'];
    buttonElement && buttonElement.addClass('disabled');
  },

  /**
   * Enables a slider button.
   *
   * The sole argument should be the string "reset", "decrease", or "increase"
   * depending on which button you want to be enabled.
   */
  enableButton: function (buttonName) {
    var buttonElement = this[buttonName + 'Element'];
    buttonElement && buttonElement.removeClass('disabled');
  },

  set_full_label: function (text) {
    this.element.find(".label").html(text);
  },

  /**
   * Init event listeners.
   */
  initEventListeners: function () {
    this.sliderView.slider.sliderVO.bind('update', $.proxy(function() {
      this.model.set({ 'user_value': this.sliderView.slider.getValue() });
    }, this));

    this.sliderView.getInfoBox().bind(
      'show', $.proxy(this.handleInputElementInfoBoxShowed, this));

    this.sliderView.bind(
      'change', $.proxy(this.checkMunicipalityNotice, this));

    this.sliderView.slider.bind(
      'change', $.proxy(this.handleSliderUpdate, this));
  },

  /**
   * Returns the number of decimal places used when formatting the value
   * shown for the input element.
   */
  getPrecision: function () {
    console.log('DEPRECATION: use formatValue instead of getPrecision');

    var lPrecisionStr = this.model.get('step_value').toString() + '';
    lPrecision = lPrecisionStr.replace('.', '').length - 1;
    return lPrecision;
  },

  /**
   * Returns a formatter on basis of the step_value.
   */
  getFormatter: function () {
    console.log('DEPRECATION: use formatValue instead of getFormatter');

    switch (this.model.get('unit')) {
      case "%":
        return SliderFormatter.numberWithSymbolFactory('%');
      case "#":
        return SliderFormatter.numberWithSymbolFactory('#');
      case "MW":
        return SliderFormatter.numberWithSymbolFactory('MW');
      case "km2":
        return SliderFormatter.numberWithSymbolFactory('km2');
      case "km":
        return SliderFormatter.numberWithSymbolFactory('km');
      case "x":
        return SliderFormatter.numberWithSymbolFactory('x');

      default:
        return null;
    }
  },

  /**
   * When the user does something on a slider this handler is invoked.
   */
  handleSliderUpdate: function () {
    this.disableUpdate = true;

    this.model.set({ 'user_value': this.quinn.value });

    this.sliderView.slider.setValue(
      this.model.get('user_value'), { noEvent: true });

    this.disableUpdate = false;
  },

  /**
   * This checks if the municipality message has been shown. It is has not
   * been shown, show it!
   */
  checkMunicipalityNotice:function () {
    if (this.model.get('semi_unadaptable') &&
          App.municipalityController.showMessage()) {

      App.municipalityController.showMunicipalityMessage();
    }
  },

  /**
   * Is called when something in the constraint model changed.
   * @override
   */
  updateHandler: function () {
    if (this.disableUpdate) {
      return;
    }

    this.sliderView.setValue(
      this.model.get('user_value'), { noEvent: true });

    return false;
  },

  /**
   * Is called when then infobox is clicked.
   * @override
   */
  handleInputElementInfoBoxShowed: function () {
    this.trigger('show');

    if (this.model.get('has_flash_movie')) {
      flowplayer('a.player', '/flash/flowplayer-3.2.6.swf');
    }
  },

  // ## Event Handlers

  /**
   * Updates elements of the UI to show the new slider value, but does _not_
   * set the value on the model (which is done later). The value is set on
   * the model as part of the Quinn onComplete callback (see `render`).
   *
   * The `fromSlider` argument indicates whether the new value has come from
   * the Quinn slider, in which case we can trust the value to fit the step,
   * min, and max values, and do not need to run the Quinn callbacks.
   *
   * TODO Buttons need may need to be enabled / disabled, such as when the new
   *      value is the minimum, the decrease button should not be clickable.
   */
  setTransientValue: function (newValue, fromSlider) {
    if (! fromSlider) {
      newValue = this.quinn.setValue(newValue);
    }

    this.valueElement.text(this.formatValue(newValue));

    return newValue;
  },

  /**
   * Resets the value of the slider to it's original value.
   */
  resetValue: function () {
    this.quinn.setValue(this.model.get('start_value'));
  },

  /**
   * Triggered when the users mouses-down on the decrease button. Reduces the
   * slider value by one step increment. If after HOLD_ACCELERATE ms the button
   * is still being held down, the slider value will continue to be decreased
   * until either the minimum value is reached, or the user lifts the button.
   */
  beginStepDown: function () {
    this.quinn.stepDown();
  },

  /**
   * Triggered when the users mouses-down on the increase button. Increases
   * the slider value by one step increment. If after HOLD_ACCELERATE ms the
   * button is still being held down, the slider value will continue to be
   * decreased until either the minimum value is reached, or the user lifts
   * the button.
   */
  beginStepUp: function () {
    this.quinn.stepUp();
  },

  /**
   * Toggles display of the slider information box.
   */
  toggleInfoBox: function () {
    this.element.toggleClass('info-box-visible');
  },

  /**
   * Used as the Quinn onComplete callback. Updates the UI.
   *
   * The Quinn onChange event is fired whenever the user moves the slider
   * but not until the onComplete event is fired has the user _finished_.
   * onChange is for updating the UI only, onComplete is where persistance
   * should be. onChange is also fired once when the is initialized.
   */
  quinnOnChange: function (newValue, quinn) {
    this.setTransientValue(newValue, true);
  },

  /**
   * Used as the Quinn onComplete callback. Takes care of setting the value
   * back to the model.
   */
  quinnOnComplete: function (newValue, quinn) {
    this.model.set({ user_value: newValue });
    this.checkMunicipalityNotice();
    this.trigger('change');
  },

  // ## Pseudo-Private Methods

  /**
   * Used to format values in the .value div. Memoized as this.formatValue.
   */
  __getFormatter: function () {
    var mStep     = this.model.get('step_value'),
        mUnit     = this.model.get('unit'),
        unit      = '',
        precision = 0;

    if (_.isNumber(mStep)) {
        precision = mStep.toString().split('.');
        precision = precision[1] ? precision[1].length : 0
    }

    if (_.isString(mUnit)) {
      switch (mUnit) {
        case "%":
        case "#":
        case "MW":
        case "km2":
        case "km":
        case "x":
          unit = ' ' + mUnit;
          break;
        // Add custom units here...
      }
    }

    return function (value) {
      return value.toFixed(precision) + unit;
    };
  },
});

// The number of milliseconds which pass before stepping up and down values
// should begin being repeated.
InputElementView.HOLD_ACCELERATE = 125;
<|endoftext|>


<commit_before>/**
 * Copyright 2014 Ian Davies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 * 		http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
define([], function() {

	var calculateBoardLevels = function(board){
			levels = [];
			for(var i = 0; i < board.questions.length; i++) {
				if (levels.indexOf(board.questions[i].level) == -1 && board.questions[i].level != 0) {
					levels.push(board.questions[i].level);
				}
			}

			levels.sort(function (a, b) {
   				return a > b ? 1 : a < b ? -1 : 0;
			});

			return levels;
	}

	var SetAssignmentsPageController = ['$scope', 'auth', 'api', 'gameBoardTitles', '$rootScope', '$window', '$timeout', function($scope, auth, api, gameBoardTitles, $rootScope, $window, $timeout) {
		$rootScope.pageTitle = "Assign Boards";

		$scope.generateGameBoardTitle = gameBoardTitles.generate;

		$scope.myGroups = api.groupManagementEndpoint.get(); // get a list of all known groups for this user.

		$scope.openedAssignPanels = []; // shows those panels currently opened
		$scope.pendingAssignment = {}; // boardId to group id mapping - allows us to know which group is being assigned which board.

		$scope.groupAssignmentInfo = {}; // map of boardId to group list - shows groups currently assigned.

		// allows the view to change which panels are open.
		$scope.toggleAssignPanel = function(board) {
			var indexOfBoard = $scope.openedAssignPanels.indexOf(board.id);
			if ($scope.openedAssignPanels.indexOf(board.id) == -1) {
				$scope.openedAssignPanels.push(board.id);
			} else {
				$scope.openedAssignPanels.splice(indexOfBoard, 1);
			}
		}

		$scope.filterOptions = [
			{label: "All Boards", val: null},
			{label: "Not Started", val: "not_attempted"},
			{label: "In Progress", val: "in_progress"},
			{label: "Completed", val: "completed"}
		];

		$scope.sortOptions = [
			{label: "Date Created", val: "created"},
			{label: "Date Visited", val: "visited"}
		];

		$scope.filterOption = $scope.filterOptions[0];
		$scope.sortOption = $scope.sortOptions[1];

		var updateBoards = function(limit) {
			$scope.setLoading(true);
			api.userGameBoards($scope.filterOption.val, $scope.sortOption.val, 0, limit).$promise.then(function(boards) {
				$scope.boards = boards;

				updateGroupAssignmentMap($scope.boards.results)

				$scope.setLoading(false);
			})
		};

		// update boards when filters have been selected
		$scope.$watch("filterOption", function(newVal, oldVal) {
			// TODO: For some reason these watch functions are being fired for no reason
			if (newVal === oldVal) {
				return;
			}
			updateBoards();
		});

		$scope.$watch("sortOption", function(newVal, oldVal) {
			if (newVal === oldVal) {
				return;
			}
			updateBoards();
		});

		// update tooltips when this changes.
		$scope.$watch("boards.results", function(newVal, oldVal){
			$timeout(function(){
				Opentip.findElements();
				//TODO: when an assignment is set the tooltip number doesn't update until a page refresh.
			}, 500);

		}, true);

		// Perform initial load
		updateBoards();

		var mergeInProgress = false;
		$scope.loadMore = function() {
			if (mergeInProgress) return;
			mergeInProgress = true;
			$scope.setLoading(true);
			api.userGameBoards($scope.filterOption.val, $scope.sortOption.val, $scope.boards.results.length).$promise.then(function(newBoards){
				// Merge new boards into results
				updateGroupAssignmentMap(newBoards.results)

				$.merge($scope.boards.results, newBoards.results);
				$scope.setLoading(false);
				mergeInProgress = false;
			});
		};

		$scope.deleteBoard = function(id, name){
			// Warn user before deleting
			var confirmation = confirm("You are about to delete "+name+" board?");
			if (confirmation){
       			// TODO: This needs to be reviewed
       			// Currently reloading boards after delete
				$scope.setLoading(true);
       			api.deleteGameBoard(id).$promise.then(function(){
			        updateBoards($scope.boards.results.length);
       			});
			}
		}

		$scope.calculateBoardLevels = calculateBoardLevels;

		var lookupAssignedGroups = function(board) {
			var groups = api.assignments.getAssignedGroups({gameId: board.id});
			return groups;
		}

		var updateGroupAssignmentMap = function(boardsToChange) {
			angular.forEach(boardsToChange, function(board, key){
				$scope.groupAssignmentInfo[board.id] = lookupAssignedGroups(board);
			});
		}

		$scope.getListOfGroups = function(listOfGroups) {
			if (listOfGroups.length == 0) {
				return "No groups have been assigned."
			}

			var listOfGroupsString = "Groups: ";

			angular.forEach(listOfGroups, function(group, key){
				listOfGroupsString = listOfGroupsString + group.groupName + ", ";
			});

			listOfGroupsString = listOfGroupsString.replace(/,\s*$/, "");

			return listOfGroupsString;
		}

		$scope.assignBoard = function(board) {
			if ($scope.pendingAssignment[board.id]) {
				var groupToAssign = $scope.pendingAssignment[board.id]._id;

				api.assignments.assignBoard({gameId: board.id, groupId: groupToAssign}).$promise.then(function(){
					updateGroupAssignmentMap([board]);
					delete $scope.pendingAssignment[board.id]; // remove from pending list.
					$scope.showToast($scope.toastTypes.Success, "Assignment Saved", "This assignment has been saved successfully.");
				}).catch(function(e){
	        		$scope.showToast($scope.toastTypes.Failure, "Board Assignment Failed", e.data.errorMessage || ("Error " + e.status));
				})
			} else {
	        	$scope.showToast($scope.toastTypes.Failure, "Board Assignment Failed", "Error: Please choose a group.");
	        }
		}

		$scope.unassignBoard = function(group, board) {
			var unassignGroup = $window.confirm('Are you sure you want to unassign this board from this group?');

			if (unassignGroup){
				api.assignments.unassignBoard({gameId: board.id, groupId: group._id}).$promise.then(function(){
					updateGroupAssignmentMap([board]);
					$scope.showToast($scope.toastTypes.Success, "Assignment Deleted", "This assignment has been unset successfully.");
				}).catch(function(e){
        			$scope.showToast($scope.toastTypes.Failure, "Board Unassignment Failed", e.data.errorMessage || ("Error " + e.status));
				});
			}
		}
	}];

	var MyAssignmentsPageController = ['$scope', 'auth', 'api', 'gameBoardTitles', '$rootScope', '$timeout', function($scope, auth, api, gameBoardTitles, $rootScope, $timeout) {

		$scope.setLoading(true);

		$rootScope.pageTitle = "My Assignments";

		$scope.generateGameBoardTitle = gameBoardTitles.generate;

		$scope.myAssignments = {};

		$scope.myAssignments.completed = [];
		$scope.myAssignments.inProgress = [];

		$scope.assignmentsVisible = $scope.myAssignments.inProgress;

		api.assignments.getMyAssignments().$promise.then(function(results) {
			angular.forEach(results, function(assignment, index) {
				if (assignment.gameboard.percentageCompleted < 100) {
					$scope.myAssignments.inProgress.push(assignment);
				} else {
					$scope.myAssignments.completed.push(assignment);
				}
			})
			$scope.setLoading(false);
		});

		$scope.toggleVisibleBoards = function(){
			if ($scope.assignmentsVisible == $scope.myAssignments.inProgress) {
				$scope.assignmentsVisible = $scope.myAssignments.completed;
			} else {
				$scope.assignmentsVisible = $scope.myAssignments.inProgress;
			}
		}

		$scope.calculateBoardLevels = calculateBoardLevels;
	}];

	return {
		SetAssignmentsPageController: SetAssignmentsPageController,
		MyAssignmentsPageController: MyAssignmentsPageController
	};
})<commit_msg>Stop delete board loading icon showing forever on set assignments page.<commit_after>/**
 * Copyright 2014 Ian Davies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 * 		http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
define([], function() {

	var calculateBoardLevels = function(board){
			levels = [];
			for(var i = 0; i < board.questions.length; i++) {
				if (levels.indexOf(board.questions[i].level) == -1 && board.questions[i].level != 0) {
					levels.push(board.questions[i].level);
				}
			}

			levels.sort(function (a, b) {
   				return a > b ? 1 : a < b ? -1 : 0;
			});

			return levels;
	}

	var SetAssignmentsPageController = ['$scope', 'auth', 'api', 'gameBoardTitles', '$rootScope', '$window', '$timeout', function($scope, auth, api, gameBoardTitles, $rootScope, $window, $timeout) {
		$rootScope.pageTitle = "Assign Boards";

		$scope.generateGameBoardTitle = gameBoardTitles.generate;

		$scope.myGroups = api.groupManagementEndpoint.get(); // get a list of all known groups for this user.

		$scope.openedAssignPanels = []; // shows those panels currently opened
		$scope.pendingAssignment = {}; // boardId to group id mapping - allows us to know which group is being assigned which board.

		$scope.groupAssignmentInfo = {}; // map of boardId to group list - shows groups currently assigned.

		// allows the view to change which panels are open.
		$scope.toggleAssignPanel = function(board) {
			var indexOfBoard = $scope.openedAssignPanels.indexOf(board.id);
			if ($scope.openedAssignPanels.indexOf(board.id) == -1) {
				$scope.openedAssignPanels.push(board.id);
			} else {
				$scope.openedAssignPanels.splice(indexOfBoard, 1);
			}
		}

		$scope.filterOptions = [
			{label: "All Boards", val: null},
			{label: "Not Started", val: "not_attempted"},
			{label: "In Progress", val: "in_progress"},
			{label: "Completed", val: "completed"}
		];

		$scope.sortOptions = [
			{label: "Date Created", val: "created"},
			{label: "Date Visited", val: "visited"}
		];

		$scope.filterOption = $scope.filterOptions[0];
		$scope.sortOption = $scope.sortOptions[1];

		var updateBoards = function(limit) {
			$scope.setLoading(true);
			api.userGameBoards($scope.filterOption.val, $scope.sortOption.val, 0, limit).$promise.then(function(boards) {
				$scope.boards = boards;

				updateGroupAssignmentMap($scope.boards.results)

				$scope.setLoading(false);
			})
		};

		// update boards when filters have been selected
		$scope.$watch("filterOption", function(newVal, oldVal) {
			// TODO: For some reason these watch functions are being fired for no reason
			if (newVal === oldVal) {
				return;
			}
			updateBoards();
		});

		$scope.$watch("sortOption", function(newVal, oldVal) {
			if (newVal === oldVal) {
				return;
			}
			updateBoards();
		});

		// update tooltips when this changes.
		$scope.$watch("boards.results", function(newVal, oldVal){
			$timeout(function(){
				Opentip.findElements();
				//TODO: when an assignment is set the tooltip number doesn't update until a page refresh.
			}, 500);

		}, true);

		// Perform initial load
		updateBoards();

		var mergeInProgress = false;
		$scope.loadMore = function() {
			if (mergeInProgress) return;
			mergeInProgress = true;
			$scope.setLoading(true);
			api.userGameBoards($scope.filterOption.val, $scope.sortOption.val, $scope.boards.results.length).$promise.then(function(newBoards){
				// Merge new boards into results
				updateGroupAssignmentMap(newBoards.results)

				$.merge($scope.boards.results, newBoards.results);
				$scope.setLoading(false);
				mergeInProgress = false;
			});
		};

		$scope.deleteBoard = function(id, name){
			// Warn user before deleting
			var confirmation = confirm("You are about to delete "+name+" board?");
			if (confirmation){
       			// TODO: This needs to be reviewed
       			// Currently reloading boards after delete
				$scope.setLoading(true);
       			api.deleteGameBoard(id).$promise.then(function(){
			        updateBoards($scope.boards.results.length);
			        $scope.setLoading(false);
       			});
			}
		}

		$scope.calculateBoardLevels = calculateBoardLevels;

		var lookupAssignedGroups = function(board) {
			var groups = api.assignments.getAssignedGroups({gameId: board.id});
			return groups;
		}

		var updateGroupAssignmentMap = function(boardsToChange) {
			angular.forEach(boardsToChange, function(board, key){
				$scope.groupAssignmentInfo[board.id] = lookupAssignedGroups(board);
			});
		}

		$scope.getListOfGroups = function(listOfGroups) {
			if (listOfGroups.length == 0) {
				return "No groups have been assigned."
			}

			var listOfGroupsString = "Groups: ";

			angular.forEach(listOfGroups, function(group, key){
				listOfGroupsString = listOfGroupsString + group.groupName + ", ";
			});

			listOfGroupsString = listOfGroupsString.replace(/,\s*$/, "");

			return listOfGroupsString;
		}

		$scope.assignBoard = function(board) {
			if ($scope.pendingAssignment[board.id]) {
				var groupToAssign = $scope.pendingAssignment[board.id]._id;

				api.assignments.assignBoard({gameId: board.id, groupId: groupToAssign}).$promise.then(function(){
					updateGroupAssignmentMap([board]);
					delete $scope.pendingAssignment[board.id]; // remove from pending list.
					$scope.showToast($scope.toastTypes.Success, "Assignment Saved", "This assignment has been saved successfully.");
				}).catch(function(e){
	        		$scope.showToast($scope.toastTypes.Failure, "Board Assignment Failed", e.data.errorMessage || ("Error " + e.status));
				})
			} else {
	        	$scope.showToast($scope.toastTypes.Failure, "Board Assignment Failed", "Error: Please choose a group.");
	        }
		}

		$scope.unassignBoard = function(group, board) {
			var unassignGroup = $window.confirm('Are you sure you want to unassign this board from this group?');

			if (unassignGroup){
				api.assignments.unassignBoard({gameId: board.id, groupId: group._id}).$promise.then(function(){
					updateGroupAssignmentMap([board]);
					$scope.showToast($scope.toastTypes.Success, "Assignment Deleted", "This assignment has been unset successfully.");
				}).catch(function(e){
        			$scope.showToast($scope.toastTypes.Failure, "Board Unassignment Failed", e.data.errorMessage || ("Error " + e.status));
				});
			}
		}
	}];

	var MyAssignmentsPageController = ['$scope', 'auth', 'api', 'gameBoardTitles', '$rootScope', '$timeout', function($scope, auth, api, gameBoardTitles, $rootScope, $timeout) {

		$scope.setLoading(true);

		$rootScope.pageTitle = "My Assignments";

		$scope.generateGameBoardTitle = gameBoardTitles.generate;

		$scope.myAssignments = {};

		$scope.myAssignments.completed = [];
		$scope.myAssignments.inProgress = [];

		$scope.assignmentsVisible = $scope.myAssignments.inProgress;

		api.assignments.getMyAssignments().$promise.then(function(results) {
			angular.forEach(results, function(assignment, index) {
				if (assignment.gameboard.percentageCompleted < 100) {
					$scope.myAssignments.inProgress.push(assignment);
				} else {
					$scope.myAssignments.completed.push(assignment);
				}
			})
			$scope.setLoading(false);
		});

		$scope.toggleVisibleBoards = function(){
			if ($scope.assignmentsVisible == $scope.myAssignments.inProgress) {
				$scope.assignmentsVisible = $scope.myAssignments.completed;
			} else {
				$scope.assignmentsVisible = $scope.myAssignments.inProgress;
			}
		}

		$scope.calculateBoardLevels = calculateBoardLevels;
	}];

	return {
		SetAssignmentsPageController: SetAssignmentsPageController,
		MyAssignmentsPageController: MyAssignmentsPageController
	};
})<|endoftext|>