<commit_before>s.Game = new Class({
  extend: s.EventEmitter,

  construct: function(options) {
    // Display load screen
    this.loadScreen = new s.LoadScreen();

    var self = this;

    /*===============================================
    =              Comms Handler Binding            =
    =================================================*/

    // Communication

    /*-----  End of  Comms Handler Binding  ------*/

    this.doRender = false;
    this.lastRender = 0;
    this.room = null;

    // Store functions that should be called before render
    this.hookedFuncs = [];

    // Oculus Rift setup
    this.oculus = new s.Oculus({
      game: this
    });

    // Bind render function permenantly
    this.render = this.render.bind(this);

    // Configure Physijs
    Physijs.scripts.worker = 'lib/physijs_worker.js';
    Physijs.scripts.ammo = 'ammo.js';

    // Create renderer
    this.renderer = new THREE.WebGLRenderer({
      antialias: true
    });

    // Enable alpha
    this.renderer.setClearColorHex(0x000000, 0);

    // Create a camera
    this.camera = new THREE.PerspectiveCamera(35, 1, 1, 300000);

    // Configure shadows
    this.renderer.shadowMapEnabled = true;
    this.renderer.shadowMapSoft = true;
    this.renderer.shadowMapCullFrontFaces = false;

    // Create the scene
    this.scene = scene = new Physijs.Scene();

    // If we want to attach the camera to an object, doing this first causes a Physijs error
    // this.scene.add(this.camera);

    // Add the renderer's canvas to the DOM
    this.el = this.renderer.domElement;
    $(document.body).append(this.el);

    // Oculus Rift split-screen effect
    this.riftCam = new THREE.OculusRiftEffect(this.renderer);
    // for testing
    // this.oculus.detected = true;

    // TODO: abstract key listening
    $(document).on('keyup', function(evt) {
      if (evt.which === 13)
        self.toggleFullScreen();
    });

    // Handle window resizes
    $(window).on('resize', this.fitWindow.bind(this));
    this.fitWindow();

    // Handle fullscreen state changes
    $(document).on('fullscreenchange mozfullscreenchange webkitfullscreenchange', this.handleFullscreenChange.bind(this));
    this.handleFullscreenChange();

    // Handle pointer lock changes
    $(document).on('pointerlockchange mozpointerlockchange webkitpointerlockchange', this.handlePointerLockChange.bind(this));
    $(document).on('pointerlockerror mozpointerlockerror webkitpointerlockerror', this.handlePointerLockError.bind(this));

    // Monitor rendering stats
    this.render_stats = new Stats();
    $(this.render_stats.domElement).css({
      position: 'absolute',
      top: 0,
      zIndex: 100
    }).appendTo(document.body);

    this.physics_stats = physics_stats = new Stats();
    $(this.physics_stats.domElement).css({
      position: 'absolute',
      top: '50px',
      zIndex: 100
    }).appendTo(document.body);

    // Physics engine statistics
    this.scene.addEventListener(
      'update',
      function() {
        physics_stats.update();
      }
    );

    // Physics engine ready state
    // TODO: This event seems to fire before the engine is actually doing anything
    this.physicsStarted = false;
    this.scene.addEventListener(
      'ready',
      function() {
        self.physicsStarted = true;
        self.tryInitialize();
      }
    );

    // Start loading models
    // TODO: Load different conditionally based on game type
    s.util.loadModels({
      models: this.models,
      complete: function(models) {
        self.modelsLoaded = true;

        // Store loaded models
        s.models = models;

        // Attempt to start the game
        self.tryInitialize(this);
      }
    });

    s.util.loadTextures({
      textures: this.textures,
      complete: function(textures) {
        self.texturesLoaded = true;

        // Store loaded textures
        s.textures = textures;

        // Attempt to start the game
        self.tryInitialize(this);
      }
    });
  },

  // Attempt to start the game (if models and physics have begun)
  tryInitialize: function() {
    if (this.modelsLoaded && this.physicsStarted && !this.initialized) {
      this.initialize();
    }
  },

  isFullScreen: function() {
    return (screen.width === window.outerWidth && screen.height === window.outerHeight);
  },

  handleFullscreenChange: function(evt) {
    if (this.isFullScreen()) {
      console.log('Full screen mode entered!');

      this.el.requestPointerLock = this.el.requestPointerLock ||
                                         this.el.mozRequestPointerLock ||
                                         this.el.webkitRequestPointerLock;
       this.el.requestPointerLock();
     } else {
       console.log('Full screen mode exited!');
     }
   },

   toggleFullScreen: function() {
     if (!this.isFullScreen()) {
       if (document.documentElement.requestFullScreen) {
         document.documentElement.requestFullScreen();
       }
       else if (document.documentElement.mozRequestFullScreen) {
         document.documentElement.mozRequestFullScreen();
       }
       else if (document.documentElement.webkitRequestFullScreen) {
         document.documentElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
       }
     }
     else {
       if (document.cancelFullScreen) {
         document.cancelFullScreen();
       }
       else if (document.mozCancelFullScreen) {
         document.mozCancelFullScreen();
       }
       else if (document.webkitCancelFullScreen) {
         document.webkitCancelFullScreen();
       }
     }
   },

   handlePointerLockChange: function() {
     if (document.mozPointerLockElement === this.el || document.webkitPointerLockElement === this.el) {
       console.log('Pointer Lock was successful.');
       this.pointerLocked = true;
     }
     else {
       console.log('Pointer Lock was lost.');
       this.pointerLocked = false;
     }
   },

   handlePointerLockError: function() {
     console.log('Error while locking pointer.');
     this.pointerLocked = false;
   },

   // Size the renderer to fit the window
   fitWindow: function() {
     this.setSize(window.innerWidth, window.innerHeight);
   },

   // Set the size of the renderer
   setSize: function(width, height) {
     this.width = width;
     this.height = height;
     this.renderer.setSize(width, height);
     if (this.camera) {
       this.camera.aspect = width/height;
       this.camera.updateProjectionMatrix();
     }
   },

   // Add a callback to the rendering loop
   hook: function(callback) {
     this.hookedFuncs.push(callback);
   },

   // Remove a callback from the rendering loop
   unhook: function(callback) {
     var index = this.hookedFuncs.indexOf(callback);
     if (~index)
       this.hookedFuncs.splice(index, 1);
   },

   // Start rendering
   start: function() {
     this.loadScreen.remove();
     this.doRender = true;
     requestAnimationFrame(this.render);
   },

   restart: function() {
    this.doRender = true;
    requestAnimationFrame(this.render);
   },

   // Stop rendering
   stop: function() {
     this.doRender = false;
   },

   // Perform render
   render: function(now) {
     if (this.doRender) {
       // Simulate physics
       this.scene.simulate();

       // Calculate the time since the last frame was rendered
       var delta = now - this.lastRender;
       this.lastRender = now;
       // Run each hooked function before rendering
       // This may need to happen BEFORE physics simulation
       this.hookedFuncs.forEach(function(func) {
         func(now, delta);
       });

       // Render main scene for Oculus if one is detected
       // otherwise render scene and radar normally.
       if (this.oculus.detected) {
         this.riftCam.render( this.scene, this.camera );
         this.riftRadar.render( this.radarScene, this.radarCamera );
       } else {
         this.renderer.render( this.scene, this.camera );
         this.radarRenderer.render( this.radarScene, this.radarCamera );
       }

       // Request the next frame to be rendered
       requestAnimationFrame(this.render);

       this.render_stats.update();
     }
   }
});
<commit_msg>Removed full screen on enter key press<commit_after>s.Game = new Class({
  extend: s.EventEmitter,

  construct: function(options) {
    // Display load screen
    this.loadScreen = new s.LoadScreen();

    var self = this;

    /*===============================================
    =              Comms Handler Binding            =
    =================================================*/

    // Communication

    /*-----  End of  Comms Handler Binding  ------*/

    this.doRender = false;
    this.lastRender = 0;
    this.room = null;

    // Store functions that should be called before render
    this.hookedFuncs = [];

    // Oculus Rift setup
    this.oculus = new s.Oculus({
      game: this
    });

    // Bind render function permenantly
    this.render = this.render.bind(this);

    // Configure Physijs
    Physijs.scripts.worker = 'lib/physijs_worker.js';
    Physijs.scripts.ammo = 'ammo.js';

    // Create renderer
    this.renderer = new THREE.WebGLRenderer({
      antialias: true
    });

    // Enable alpha
    this.renderer.setClearColorHex(0x000000, 0);

    // Create a camera
    this.camera = new THREE.PerspectiveCamera(35, 1, 1, 300000);

    // Configure shadows
    this.renderer.shadowMapEnabled = true;
    this.renderer.shadowMapSoft = true;
    this.renderer.shadowMapCullFrontFaces = false;

    // Create the scene
    this.scene = scene = new Physijs.Scene();

    // If we want to attach the camera to an object, doing this first causes a Physijs error
    // this.scene.add(this.camera);

    // Add the renderer's canvas to the DOM
    this.el = this.renderer.domElement;
    $(document.body).append(this.el);

    // Oculus Rift split-screen effect
    this.riftCam = new THREE.OculusRiftEffect(this.renderer);
    // for testing
    // this.oculus.detected = true;

    // Handle window resizes
    $(window).on('resize', this.fitWindow.bind(this));
    this.fitWindow();

    // Handle fullscreen state changes
    $(document).on('fullscreenchange mozfullscreenchange webkitfullscreenchange', this.handleFullscreenChange.bind(this));
    this.handleFullscreenChange();

    // Handle pointer lock changes
    $(document).on('pointerlockchange mozpointerlockchange webkitpointerlockchange', this.handlePointerLockChange.bind(this));
    $(document).on('pointerlockerror mozpointerlockerror webkitpointerlockerror', this.handlePointerLockError.bind(this));

    // Monitor rendering stats
    this.render_stats = new Stats();
    $(this.render_stats.domElement).css({
      position: 'absolute',
      top: 0,
      zIndex: 100
    }).appendTo(document.body);

    this.physics_stats = physics_stats = new Stats();
    $(this.physics_stats.domElement).css({
      position: 'absolute',
      top: '50px',
      zIndex: 100
    }).appendTo(document.body);

    // Physics engine statistics
    this.scene.addEventListener(
      'update',
      function() {
        physics_stats.update();
      }
    );

    // Physics engine ready state
    // TODO: This event seems to fire before the engine is actually doing anything
    this.physicsStarted = false;
    this.scene.addEventListener(
      'ready',
      function() {
        self.physicsStarted = true;
        self.tryInitialize();
      }
    );

    // Start loading models
    // TODO: Load different conditionally based on game type
    s.util.loadModels({
      models: this.models,
      complete: function(models) {
        self.modelsLoaded = true;

        // Store loaded models
        s.models = models;

        // Attempt to start the game
        self.tryInitialize(this);
      }
    });

    s.util.loadTextures({
      textures: this.textures,
      complete: function(textures) {
        self.texturesLoaded = true;

        // Store loaded textures
        s.textures = textures;

        // Attempt to start the game
        self.tryInitialize(this);
      }
    });
  },

  // Attempt to start the game (if models and physics have begun)
  tryInitialize: function() {
    if (this.modelsLoaded && this.physicsStarted && !this.initialized) {
      this.initialize();
    }
  },

  isFullScreen: function() {
    return (screen.width === window.outerWidth && screen.height === window.outerHeight);
  },

  handleFullscreenChange: function(evt) {
    if (this.isFullScreen()) {
      console.log('Full screen mode entered!');

      this.el.requestPointerLock = this.el.requestPointerLock ||
                                         this.el.mozRequestPointerLock ||
                                         this.el.webkitRequestPointerLock;
       this.el.requestPointerLock();
     } else {
       console.log('Full screen mode exited!');
     }
   },

   toggleFullScreen: function() {
     if (!this.isFullScreen()) {
       if (document.documentElement.requestFullScreen) {
         document.documentElement.requestFullScreen();
       }
       else if (document.documentElement.mozRequestFullScreen) {
         document.documentElement.mozRequestFullScreen();
       }
       else if (document.documentElement.webkitRequestFullScreen) {
         document.documentElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
       }
     }
     else {
       if (document.cancelFullScreen) {
         document.cancelFullScreen();
       }
       else if (document.mozCancelFullScreen) {
         document.mozCancelFullScreen();
       }
       else if (document.webkitCancelFullScreen) {
         document.webkitCancelFullScreen();
       }
     }
   },

   handlePointerLockChange: function() {
     if (document.mozPointerLockElement === this.el || document.webkitPointerLockElement === this.el) {
       console.log('Pointer Lock was successful.');
       this.pointerLocked = true;
     }
     else {
       console.log('Pointer Lock was lost.');
       this.pointerLocked = false;
     }
   },

   handlePointerLockError: function() {
     console.log('Error while locking pointer.');
     this.pointerLocked = false;
   },

   // Size the renderer to fit the window
   fitWindow: function() {
     this.setSize(window.innerWidth, window.innerHeight);
   },

   // Set the size of the renderer
   setSize: function(width, height) {
     this.width = width;
     this.height = height;
     this.renderer.setSize(width, height);
     if (this.camera) {
       this.camera.aspect = width/height;
       this.camera.updateProjectionMatrix();
     }
   },

   // Add a callback to the rendering loop
   hook: function(callback) {
     this.hookedFuncs.push(callback);
   },

   // Remove a callback from the rendering loop
   unhook: function(callback) {
     var index = this.hookedFuncs.indexOf(callback);
     if (~index)
       this.hookedFuncs.splice(index, 1);
   },

   // Start rendering
   start: function() {
     this.loadScreen.remove();
     this.doRender = true;
     requestAnimationFrame(this.render);
   },

   restart: function() {
    this.doRender = true;
    requestAnimationFrame(this.render);
   },

   // Stop rendering
   stop: function() {
     this.doRender = false;
   },

   // Perform render
   render: function(now) {
     if (this.doRender) {
       // Simulate physics
       this.scene.simulate();

       // Calculate the time since the last frame was rendered
       var delta = now - this.lastRender;
       this.lastRender = now;
       // Run each hooked function before rendering
       // This may need to happen BEFORE physics simulation
       this.hookedFuncs.forEach(function(func) {
         func(now, delta);
       });

       // Render main scene for Oculus if one is detected
       // otherwise render scene and radar normally.
       if (this.oculus.detected) {
         this.riftCam.render( this.scene, this.camera );
         this.riftRadar.render( this.radarScene, this.radarCamera );
       } else {
         this.renderer.render( this.scene, this.camera );
         this.radarRenderer.render( this.radarScene, this.radarCamera );
       }

       // Request the next frame to be rendered
       requestAnimationFrame(this.render);

       this.render_stats.update();
     }
   }
});
<|endoftext|>


<commit_before>////////////////////////////////////////////////////
////////////////////////////////////////////////////
// docuK Process
////////////////////////////////////////////////////
////////////////////////////////////////////////////
kipid.docuKProcess=function docuK(kipid, $, docuKI, undefined){
	////////////////////////////////////////////////////
	// Possible duplicate id is handled.
	////////////////////////////////////////////////////
	docuKI=(isNaN(docuKI)||docuKI<0)?0:parseInt(docuKI);
	kipid.logPrint("

docuK-"+docuKI+" scripts started!
If this log is not closed automatically, there must be an error somewhere in your document or scripts.");
	var docuK=kipid.docuK.eq(docuKI);
	if (docuK.is(".rendered")){
		kipid.logPrint("

docuK-"+docuKI+" is already rendered.");
		return;
	}

	var postId="-in-docuK"+docuKI;
	var postIdRegEx=new RegExp(postId+"$");
	if (docuK.is(".noDIdHandle")){
		postId="";
	} else{
		docuK.find("[id]").each(function(){
			var $this=$(this);
			$this[0].id+=postId;
		});
	}

	////////////////////////////////////////////////////
	// Style change widget.
	////////////////////////////////////////////////////
	var fontSizeAndLineHeight=(docuKI===1)?
		'<form><button type="button" onclick="kipid.CfontSize(-1)" style="font-size:1em">A</button>'
		+'<button type="button" onclick="kipid.CfontSize(1)" style="font-size:1.4em">A</button></form> '
		+'<form><button type="button" onclick="kipid.ClineHeight(-1)" style="font-size:1.3em">=</button>'
		+'<button type="button" onclick="kipid.ClineHeight(1)" style="font-size:1.3em">〓</button></form> '
		:"";
	docuK.prepend(
		'
'
		+'<form><input id="button'+docuKI+'-Dark" type="radio" name="mode" value="Dark" onclick="kipid.Cmode(this.value)">Dark'
		+'</input><input id="button'+docuKI+'-Bright" type="radio" name="mode" value="Bright" onclick="kipid.Cmode(this.value)">Bright</input></form> '
		+'<form><input class="emph" type="text" name="font" value="맑은 고딕" style="font-family:\'맑은 고딕\'; font-size:1.2em; width:73px; height:23px; text-align:center" onchange="kipid.CfontFamily(this.value)"></input></form> '
		+fontSizeAndLineHeight
		+'<form><button type="button" onclick="MathJax.Hub.Queue([\'Typeset\', MathJax.Hub])" style="width:auto; padding:0 .5em">All Maths</button></form> '
		+'<form><button type="button" onclick="kipid.log.toggle()" style="width:auto; padding:0 .5em">DocuK Log</button></form> '
		+'

'
	);

	////////////////////////////////////////////////////
	// Scrollable switching of 'pre.prettyprint'.
	////////////////////////////////////////////////////
	docuK.find("pre.prettyprint").wrap("

").before('
On the left side of codes is there a hiden button to toggle/switch scrollability ({max-height:some} or {max-height:none}).

');
	kipid.logPrint("

<codeprint> tags are printed to corresponding <pre> tags, only when the tags exist in the document.");

	////////////////////////////////////////////////////
	// Numbering section, making table of contents, and numbering eqq (formatting to MathJax also) and figure tags
	////////////////////////////////////////////////////
	var secs=docuK.find(">.sec"), subsecs, subsubsecs, secContentsId="";
	var secI, secIH2, subsecJH3, subsubsecKH4;
	var secN=0, secITxt="", subsecI=0, subsubsecI=0, tocHtml="", txt="", secId="", secPreTxt="";
	var eqqs, eqN="", eqC="", figs;
	function fTocHtml(numbering){
		var secN=(numbering===undefined||numbering)?"secN":"none";
		return "<h"+hN+">"
		+""
			+""+secPreTxt+"."
			+txt
		+"</h"+hN+">";
	}
	function fSecHtml(numbering){
		var secN="none", endA0="", endA1="";
		if (numbering===undefined||numbering){
			secN="secN"; endA0=""; endA1="";
		}
		return "T"
		+""
			+""+secPreTxt+"."
		+endA0+txt+endA1;
	}
	function fEqqHtml(){
		return '
'
			+'
('+eqN+')
'
			+'
'+eqC+'
'
		+'
';
	}
	for (var i=0;i<secs.length;i++){
		secI=secs.eq(i);
		secIH2=secI.find("h2:first-child");
		if (secIH2.exists() && !secIH2.is(".notSec")){ // exclude ".sec>h1" and ".sec>h2.notSec" in ToC
			hN="2"; txt=secIH2.html();
			if (secIH2.is(".no-sec-N")){
				secPreTxt=secId=secITxt=(secIH2.is("[id]"))?secIH2.attr('id').replace(/^sec-/i,'').replace(postIdRegEx,''):"secPreTxt"+docuKI+"-"+i;
				tocHtml+=fTocHtml(false);
				secIH2.html(fSecHtml(false));
			} else {
				secN++;
				secPreTxt=secId=secITxt=secN.toString();
				tocHtml+=fTocHtml();
				secIH2.html(fSecHtml());
			}

			if (!secI.is(".noToggleUI")){
				secContentsId="sec"+docuKI+"-"+secITxt+"-contents";
				secI.append("

▲ Hide

");
				secI.contents().slice(1).wrapAll("

");
				secIH2.after("
▼ Show/Hide
");
				secI.append("

");
			}

			subsecs=secI.find(".subsec"); subsecI=0;
			for (var j=0;j<subsecs.length;j++){
				subsecJH3=subsecs.eq(j).find("h3:first-child");
				hN="3"; subsecI++; secId=secITxt+"-"+subsecI; secPreTxt=secITxt+"."+subsecI; txt=subsecJH3.html();
				tocHtml+=fTocHtml();
				subsecJH3.html(fSecHtml());

				subsubsecs=subsecs.eq(j).find(".subsubsec"); subsubsecI=0;
				for (var k=0;k<subsubsecs.length;k++){
					subsubsecKH4=subsubsecs.eq(k).find("h4:first-child");
					hN="4"; subsubsecI++; secId=secITxt+"-"+subsecI+"-"+subsubsecI; secPreTxt=secITxt+"."+subsecI+"."+subsubsecI; txt=subsubsecKH4.html();
					tocHtml+=fTocHtml();
					subsubsecKH4.html(fSecHtml());
				}
			}
		} else {
			secITxt="x";
		}
		eqqs=secI.find("eqq");
		for(j=0;j<eqqs.length;j++){
			eqN=secITxt+"-"+(j+1).toString();
			eqC=eqqs.eq(j).html().trim();
			eqqs.eq(j).html(fEqqHtml());
		}
		figs=secI.find("figure");
		for(j=0;j<figs.length;j++){
			figN=secITxt+"-"+(j+1).toString();
			figs.eq(j).find(".caption").html(function(ith,orgTxt){return "Fig. ("+figN+"): "+orgTxt.trim();});
		}
	}
	secs.find(".toc").html(tocHtml);
	kipid.logPrint("

Table of Contents is created.

Auto numberings of sections (div.sec>h2, div.subsec>h3, div.subsubsec>h4), <eqq> tags, and <figure> tags are done.");

	////////////////////////////////////////////////////
	// Make 'cite' tags bubble-refer references in ".docuK ol.refs>li".
	// Make 'refer' tags bubble-refer equations (eqq tag) or figures (figure tag). Any tag with id can be bubble-refered with refer tag.
	////////////////////////////////////////////////////
	function pad(str, max){
		str=str.toString();
		return str.length<max?pad("0"+str,max):str;
	}
	var refN="", preRefHtml="", refHtml="", citeN="";
	function fCiteHtml(){
		var str='
'
			+refN
			+'
'
				+'
'+preRefHtml+refHtml+'
'
				+'

'
				+'
<svg>'
					+'<g style="stroke:white;stroke-width:23%">'
						+'<line x1="20%" y1="20%" x2="80%" y2="80%"/>'
						+'<line x1="80%" y1="20%" x2="20%" y2="80%"/>'
					+'</g>'
					+'✖'
				+'</svg>
'
			+'

';
		if (kipid.browserWidth<321){
			str=str.replace(/]*>[^<]*<\/iframe>/ig, 'In bubble refs, iframe (or youtube video) is intentionally NOT supported for various reasons (security, and cross browsing). See it in the original position of the iframe (video).'); // 말풍선에서 비디오 등의 iframe을 의도적으로 지원하지 않았습니다. 원래의 위치에서 보세요.
		}
		return str;
	}
	var refs=docuK.find("ol.refs>li")
	for(i=0;i<refs.length;i++){ // ref [i+1] with id
		refs.eq(i).prepend("["+pad(i+1,2)+"]");
	}
	var refers=docuK.find("cite,refer"), referI, refered;
	refers.html('( No refer. )');
	for(i=0;i<refers.length;i++){
		referI=refers.eq(i);
		if (referI.is("[class]")){
			refered=docuK.find("#"+referI.attr("class")+postId);
			if (refered.exists()){
				citeN=(i+1).toString()+"-"+referI.attr("class")+postId;
				refHtml=refered.html().trim().replace(/\bid\s*=/gi,'psudoId=');
				refN=refered.find(".number").html();
				referI.html(fCiteHtml());
			}
		}
	}
	kipid.logPrint("

<cite> and <refer> tags are rendered to show bubble reference.");

	docuK.addClass("rendered");
};

////////////////////////////////////////////////////
////////////////////////////////////////////////////
// docuK post-Process
////////////////////////////////////////////////////
////////////////////////////////////////////////////
(function(kipid, $, undefined){
	var docuK=kipid.docuK=$(".docuK");

	////////////////////////////////////////////////////
	// Showing disableQ0 only in width>321.
	////////////////////////////////////////////////////
	if (kipid.browserWidth>321){
		docuK.find(".disableQ0").html(function(ith,orgText){
			kipid.logPrint("

\".disableQ0\"s are enabled at vertical position of "+(100*$(this).offset().top/$(document).height()).toPrecision(3)+"% of document.");
			return orgText.replace(//g,'');
		});
	}

	////////////////////////////////////////////////////
	// Printing codes in <codeprint> with id into
.
	////////////////////////////////////////////////////
	var codeprints=$("codeprint");
	for (var i=0;i<codeprints.length;i++){
		kipid.printCode(codeprints.eq(i).attr('id'));
	}

	////////////////////////////////////////////////////
	// <eq> and <eqq> tags to MathJax format
	////////////////////////////////////////////////////
	var eqs=$("eq");
	for (var i=0;i<eqs.length;i++){
		eqs.eq(i).html(function(ith,orgTxt){return "\\( "+orgTxt.trim()+" \\)";});
	}
	var eqqs=$("eqq");
	for (var i=0;i<eqqs.length;i++){
		eqqs.eq(i).html(function(ith,orgTxt){return "\\[ "+orgTxt.trim()+" \\]";});
	}
	kipid.logPrint("

<eq> and <eqq> tags are rendered to MathJax format enclosed by \\ ( and \\ ).");

	////////////////////////////////////////////////////
	// docuK process.
	////////////////////////////////////////////////////
	docuK.has("script").addClass("noDIdHandle");
	var k=docuK.length;
	for(var i=1;i<k;i++){
		kipid.docuKProcess(kipid, jQuery, i);
	}

	kipid.TFontSize=docuK.find(".TFontSize");
	kipid.TLineHeight=docuK.find(".TLineHeight");
	kipid.deviceInfo=docuK.find(".deviceInfo");

	kipid.bubbleRefs=docuK.find(".bubbleRef"); // for function kipid.ShowBR

	var inRefs=docuK.find(".inRef");
	// Centering arrow.
	inRefs.each(function(){
		var $elem=$(this);
		var width=parseFloat($elem.width());
		var $arrow=$elem.find(".arrow");
		var borderWidth=parseFloat($arrow.css("borderWidth"));
		var fontSize=parseFloat($arrow.css("fontSize"));
		$arrow.css({marginLeft:((width/2-borderWidth)/fontSize).toFixed(2)+"em"});
	});
	// Delayed-Load in bubble ref.
	inRefs.on("mouseenter.delayedLoad", function(){
		kipid.logPrint("
Do delayed-load in bubble ref.");
		$(window).trigger("scroll.delayedLoad");
		$(this).off("mouseenter.delayedLoad");
	});

	////////////////////////////////////////////////////
	// On ready.
	////////////////////////////////////////////////////
	$(document).ready(function(){
		// Hiding hiden sections.
		docuK.find(".sec.hiden").find(">.sec-contents").css({display:"none"});

		////////////////////////////////////////////////////
		// Printing Styles
		////////////////////////////////////////////////////
		// kipid.TFontSize.html((kipid.fontSize*1.8).toFixed(1)+"px");
		// kipid.TLineHeight.html((kipid.lineHeight10/10).toFixed(1));
		// kipid.deviceInfo.html("browser width: "+kipid.browserWidth);
		kipid.browserWidth=0;
		$(window).trigger("resize.deviceInfo");
		kipid.logPrint("

Current styles (dark/bright mode, font-family, font-size, line-height) are shown.");

		////////////////////////////////////////////////////
		// Initial Delayed Load.
		////////////////////////////////////////////////////
		kipid.delayedElems=docuK.find("[delayed-src], [delayed-bgimage]");
		kipid.logPrint("

There are "+kipid.delayedElems.length+" delayed elements.");
		$(window).trigger("scroll.delayedLoad");
		$(window).off("scroll.delayedLoad");

		////////////////////////////////////////////////////
		// MathJax PreProcess.
		////////////////////////////////////////////////////
		MathJax.Hub.Queue(["PreProcess",MathJax.Hub]);
		MathJax.Hub.Queue(function(){
			kipid.delayedElems=kipid.delayedElems.add(".MathJax_Preview");
			kipid.logPrint("

\".MathJax_Preview\" are added to kipid.delayedElems. Now its length is: "+kipid.delayedElems.length);
			$(window).on("scroll.delayedLoad", kipid.delayedLoadByScroll);
		});

		////////////////////////////////////////////////////
		// google code prettify js script is added.
		////////////////////////////////////////////////////
		if (docuK.find(".prettyprint").exists()){
			var gcp=document.createElement('script');
			gcp.defer="";
			gcp.src="http://cfs.tistory.com/custom/blog/146/1468360/skin/images/run_prettify.js";
			(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(gcp);
			kipid.logPrint("

Google code prettyfy.js is loaded since pre.prettyprint is in your document.");
		}

		////////////////////////////////////////////////////
		// ShortKeys (including default 'processShortcut(event)' of tistory.)
		////////////////////////////////////////////////////
		kipid.hLists=$(".docuK .sec>h1,.docuK .sec>h2,.docuK .subsec>h3,.docuK .subsubsec>h4");
		kipid.processShortKey=function(event){
			if (isIE){
				event=window.event;
				event.target=event.srcElement;
			}
			if (event.altKey||event.ctrlKey||event.metaKey) return;
			switch (event.target.nodeName) {
				case "INPUT":
				case "SELECT":
				case "TEXTAREA":
					return;
			}
			switch (event.keyCode){
				case 70: //F = 70
				case 68: //D = 68
					var scrollTop=$(window).scrollTop();
					var i=0, k=kipid.hLists.length;
					var location;
					var hI;

					if (event.keyCode===70){
						scrollTop+=30;
						for (i=0;i<k;i++){
							hI=kipid.hLists.eq(i);
							if (hI.is(":visible")&&scrollTop<hI.offset().top){ break; }
						}
						if (i===k){
							// hI=kipid.hLists.eq(0);
							alert("This is the last section.");
							return;
						}
					} else{
						scrollTop-=30;
						for (i=k-1;i>=0;i--){
							hI=kipid.hLists.eq(i);
							if (hI.is(":visible")&&scrollTop>hI.offset().top){ break; }
						}
						if (i===-1){
							// hI=kipid.hLists.eq(k-1);
							alert("This is the first section.");
							return;
						}
					}
					location=hI.is("[id]")? "#"+hI.attr("id") : hI.offset().top;

					if (isNaN(location)){
						window.location = location;
					} else{
						$(window).scrollTop(location);
					}
					break;
				case 76: //L = 76
					window.location = "/entry/Lists"
					break;
				default:
					processShortcut(event);
			}
		}
		document.onkeydown=kipid.processShortKey;
		var shortkeyDesc=$("#shortkey>ul");
		if (shortkeyDesc.exists()){
			shortkeyDesc.prepend(
				"
D: Previous Section
"
				+"
F: Forward Section
"
				+"
L: To the Lists
"
			);
		}
		kipid.logPrint("

New ShortKeys (D, F, L) are set.")

		////////////////////////////////////////////////////
		// Closing docuK Log.
		////////////////////////////////////////////////////
		kipid.logPrint("

docuK scripts are all done. Then this log is closing in 1.0 sec.");
		setTimeout(function(){kipid.log.hide();}, 0);
	});
})(window.kipid, jQuery);<commit_msg>Some moved to prepare, short key processes<commit_after>////////////////////////////////////////////////////
////////////////////////////////////////////////////
// docuK post-Process
////////////////////////////////////////////////////
////////////////////////////////////////////////////
(function(kipid, $, undefined){
	var docuK=kipid.docuK=$(".docuK");

	////////////////////////////////////////////////////
	// Showing disableQ0 only in width>321.
	////////////////////////////////////////////////////
	if (kipid.browserWidth>321){
		docuK.find(".disableQ0").html(function(ith,orgText){
			kipid.logPrint("

\".disableQ0\"s are enabled at vertical position of "+(100*$(this).offset().top/$(document).height()).toPrecision(3)+"% of document.");
			return orgText.replace(//g,'');
		});
	}

	////////////////////////////////////////////////////
	// Printing codes in <codeprint> with id into
.
	////////////////////////////////////////////////////
	var codeprints=$("codeprint");
	for (var i=0;i<codeprints.length;i++){
		kipid.printCode(codeprints.eq(i).attr('id'));
	}

	////////////////////////////////////////////////////
	// <eq> and <eqq> tags to MathJax format
	////////////////////////////////////////////////////
	var eqs=$("eq");
	for (var i=0;i<eqs.length;i++){
		eqs.eq(i).html(function(ith,orgTxt){return "\\( "+orgTxt.trim()+" \\)";});
	}
	var eqqs=$("eqq");
	for (var i=0;i<eqqs.length;i++){
		eqqs.eq(i).html(function(ith,orgTxt){return "\\[ "+orgTxt.trim()+" \\]";});
	}
	kipid.logPrint("

<eq> and <eqq> tags are rendered to MathJax format enclosed by \\ ( and \\ ).");

	////////////////////////////////////////////////////
	// docuK process.
	////////////////////////////////////////////////////
	docuK.has("script").addClass("noDIdHandle");
	var k=docuK.length;
	for(var i=1;i<k;i++){
		kipid.docuKProcess(kipid, jQuery, i);
	}

	kipid.TFontSize=docuK.find(".TFontSize");
	kipid.TLineHeight=docuK.find(".TLineHeight");
	kipid.deviceInfo=docuK.find(".deviceInfo");

	kipid.bubbleRefs=docuK.find(".bubbleRef"); // for function kipid.ShowBR

	var inRefs=docuK.find(".inRef");
	// Centering arrow.
	inRefs.each(function(){
		var $elem=$(this);
		var width=parseFloat($elem.width());
		var $arrow=$elem.find(".arrow");
		var borderWidth=parseFloat($arrow.css("borderWidth"));
		var fontSize=parseFloat($arrow.css("fontSize"));
		$arrow.css({marginLeft:((width/2-borderWidth)/fontSize).toFixed(2)+"em"});
	});
	// Delayed-Load in bubble ref.
	inRefs.on("mouseenter.delayedLoad", function(){
		kipid.logPrint("
Do delayed-load in bubble ref.");
		$(window).trigger("scroll.delayedLoad");
		$(this).off("mouseenter.delayedLoad");
	});

	////////////////////////////////////////////////////
	// On ready.
	////////////////////////////////////////////////////
	$(document).ready(function(){
		// Hiding hiden sections.
		docuK.find(".sec.hiden").find(">.sec-contents").css({display:"none"});

		////////////////////////////////////////////////////
		// Printing Styles
		////////////////////////////////////////////////////
		// kipid.TFontSize.html((kipid.fontSize*1.8).toFixed(1)+"px");
		// kipid.TLineHeight.html((kipid.lineHeight10/10).toFixed(1));
		// kipid.deviceInfo.html("browser width: "+kipid.browserWidth);
		kipid.browserWidth=0;
		$(window).trigger("resize.deviceInfo");
		kipid.logPrint("

Current styles (dark/bright mode, font-family, font-size, line-height) are shown.");

		////////////////////////////////////////////////////
		// Initial Delayed Load.
		////////////////////////////////////////////////////
		kipid.delayedElems=docuK.find("[delayed-src], [delayed-bgimage]");
		kipid.logPrint("

There are "+kipid.delayedElems.length+" delayed elements.");
		$(window).trigger("scroll.delayedLoad");
		$(window).off("scroll.delayedLoad");

		////////////////////////////////////////////////////
		// MathJax PreProcess.
		////////////////////////////////////////////////////
		MathJax.Hub.Queue(["PreProcess",MathJax.Hub]);
		MathJax.Hub.Queue(function(){
			kipid.delayedElems=kipid.delayedElems.add(".MathJax_Preview");
			kipid.logPrint("

\".MathJax_Preview\" are added to kipid.delayedElems. Now its length is: "+kipid.delayedElems.length);
			$(window).on("scroll.delayedLoad", kipid.delayedLoadByScroll);
		});

		////////////////////////////////////////////////////
		// google code prettify js script is added.
		////////////////////////////////////////////////////
		if (docuK.find(".prettyprint").exists()){
			var gcp=document.createElement('script');
			gcp.defer="";
			gcp.src="http://cfs.tistory.com/custom/blog/146/1468360/skin/images/run_prettify.js";
			(document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(gcp);
			kipid.logPrint("

Google code prettyfy.js is loaded since pre.prettyprint is in your document.");
		}

		////////////////////////////////////////////////////
		// ShortKeys (including default 'processShortcut(event)' of tistory.)
		////////////////////////////////////////////////////
		kipid.hLists=$("#content .titleWrap>h2,.docuK .sec>h1,.docuK .sec>h2,.docuK .subsec>h3,.docuK .subsubsec>h4");
		kipid.processShortKey=function(event){
			if (event.altKey||event.ctrlKey||event.metaKey) return;
			switch (event.target.nodeName) {
				case "INPUT": case "SELECT": case "TEXTAREA": return;
			}
			switch (event.keyCode){
				case 70: //F = 70
				case 68: //D = 68
					var scrollTop=$(window).scrollTop();
					var i=0, k=kipid.hLists.length;
					var location;
					var hI;

					if (event.keyCode===70){
						scrollTop+=10;
						for (i=0;i<k;i++){
							hI=kipid.hLists.eq(i);
							if (hI.is(":visible")&&scrollTop<hI.offset().top){ break; }
						}
						if (i===k){
							// hI=kipid.hLists.eq(0);
							// alert("This is the last section.");
							return;
						}
					} else{
						scrollTop-=10;
						for (i=k-1;i>=0;i--){
							hI=kipid.hLists.eq(i);
							if (hI.is(":visible")&&scrollTop>hI.offset().top){ break; }
						}
						if (i===-1){
							// hI=kipid.hLists.eq(k-1);
							// alert("This is the first section.");
							return;
						}
					}
					$(window).scrollTop(hI.offset().top);
					break;
				case 76: //L = 76
					window.location = "/category/0"
					break;
				case 90: //Z
					if ($("#recentEntries").exists()) $(window).scrollTop($("#recentEntries").offset().top);
					break;
				case 88: //X
					if ($("#recentComments").exists()) $(window).scrollTop($("#recentComments").offset().top);
					break;
				case 67: //C
					if ($("#recentTrackback").exists()) $(window).scrollTop($("#recentTrackback").offset().top);
					break;
				default:
					if (window['processShortcut']!==undefined) processShortcut(event);
			}
		}
		document.onkeydown=kipid.processShortKey;
		var shortkeyDesc=$("#shortkey>ul");
		if (shortkeyDesc.exists()){
			shortkeyDesc.prepend(
				"
D: Previous Section
"
				+"
F: Forward Section
"
				+"
L: To the [Lists]
"
			);
		}
		kipid.logPrint("

New ShortKeys (D, F, L) are set.");

		////////////////////////////////////////////////////
		// Closing docuK Log.
		////////////////////////////////////////////////////
		kipid.logPrint("

docuK scripts are all done. Then this log is closing in 1.0 sec.");
		setTimeout(function(){kipid.log.hide();}, 0);
	});
})(window.kipid, jQuery);<|endoftext|>


<commit_before>import $ from 'jquery';
import createHash from 'sha.js';

import { getCurrentUser } from 'girder/auth';
import CollectionModel from 'girder/models/CollectionModel';
import { restRequest } from 'girder/rest';

const termsAcceptedFallback = {};

CollectionModel.prototype.hasTerms = function () {
    // An empty string also means there are no terms.
    return Boolean(this.get('terms'));
};

CollectionModel.prototype.currentUserHasAcceptedTerms = function () {
    const termsHash = this._hashTerms();
    const currentUser = getCurrentUser();
    if (currentUser) {
        const userAcceptedTerms = currentUser.get('terms');
        // Lodash's _.get would be nice here
        return userAcceptedTerms &&
            userAcceptedTerms.collection &&
            userAcceptedTerms.collection[this.id] &&
            (userAcceptedTerms.collection[this.id].hash === termsHash);
    } else {
        const storageKey = `terms.collection.${this.id}`;
        return (window.localStorage.getItem(storageKey) === termsHash) ||
               (termsAcceptedFallback[this.id] === termsHash);
    }
};

CollectionModel.prototype.currentUserSetAcceptTerms = function () {
    const termsHash = this._hashTerms();
    const currentUser = getCurrentUser();
    if (currentUser) {
        return restRequest({
            url: `collection/${this.id}/acceptTerms`,
            method: 'POST',
            data: {
                termsHash: termsHash
            }
        })
            .done(() => {
                // Even if this endpoint returned an updated copy of the user document, it wouldn't
                // be safe to just "setCurrentUser" with that document here, since the login method
                // performs some special transformations (e.g. setting a "token" attribute) before
                // instantiating a new UserModel, and it would be too fragile to reproduce those
                // here. We also don't want to trigger a brand-new login. So, just update the
                // currentUser's "terms" attribute in-place, triggering a "change" event.
                const userAcceptedTerms = currentUser.get('terms') || {};
                // This code would be much cleaner with _.merge from Lodash.
                userAcceptedTerms.collection = userAcceptedTerms.collection || {};
                userAcceptedTerms.collection[this.id] = termsHash;
                currentUser.set('terms', userAcceptedTerms);
            });
    } else {
        const storageKey = `terms.collection.${this.id}`;
        try {
            window.localStorage.setItem(storageKey, termsHash);
        } catch (e) {
            termsAcceptedFallback[this.id] = termsHash;
        }
        return $.Deferred().resolve().promise();
    }
};

CollectionModel.prototype._hashTerms = function () {
    window.hex = createHash('sha256').update(this.get('terms'));
    return createHash('sha256').update(this.get('terms')).digest('base64');
};
<commit_msg>Fix an bug when storing the time that terms were accepted<commit_after>import $ from 'jquery';
import createHash from 'sha.js';

import { getCurrentUser } from 'girder/auth';
import CollectionModel from 'girder/models/CollectionModel';
import { restRequest } from 'girder/rest';

const termsAcceptedFallback = {};

CollectionModel.prototype.hasTerms = function () {
    // An empty string also means there are no terms.
    return Boolean(this.get('terms'));
};

CollectionModel.prototype.currentUserHasAcceptedTerms = function () {
    const termsHash = this._hashTerms();
    const currentUser = getCurrentUser();
    if (currentUser) {
        const userAcceptedTerms = currentUser.get('terms');
        // Lodash's _.get would be nice here
        return userAcceptedTerms &&
            userAcceptedTerms.collection &&
            userAcceptedTerms.collection[this.id] &&
            (userAcceptedTerms.collection[this.id].hash === termsHash);
    } else {
        const storageKey = `terms.collection.${this.id}`;
        return (window.localStorage.getItem(storageKey) === termsHash) ||
               (termsAcceptedFallback[this.id] === termsHash);
    }
};

CollectionModel.prototype.currentUserSetAcceptTerms = function () {
    const termsHash = this._hashTerms();
    const currentUser = getCurrentUser();
    if (currentUser) {
        return restRequest({
            url: `collection/${this.id}/acceptTerms`,
            method: 'POST',
            data: {
                termsHash: termsHash
            }
        })
            .done(() => {
                // Even if this endpoint returned an updated copy of the user document, it wouldn't
                // be safe to just "setCurrentUser" with that document here, since the login method
                // performs some special transformations (e.g. setting a "token" attribute) before
                // instantiating a new UserModel, and it would be too fragile to reproduce those
                // here. We also don't want to trigger a brand-new login. So, just update the
                // currentUser's "terms" attribute in-place, triggering a "change" event.
                const userAcceptedTerms = currentUser.get('terms') || {};
                // This code would be much cleaner with _.merge from Lodash.
                userAcceptedTerms.collection = userAcceptedTerms.collection || {};
                userAcceptedTerms.collection[this.id] = {
                    hash: termsHash,
                    // 'accepted' is from a server-set timestamp, so we don't know it here. However,
                    // its value is irreverent, as it's for auditing purposes only.
                    accepted: null
                };
                currentUser.set('terms', userAcceptedTerms);
            });
    } else {
        const storageKey = `terms.collection.${this.id}`;
        try {
            window.localStorage.setItem(storageKey, termsHash);
        } catch (e) {
            termsAcceptedFallback[this.id] = termsHash;
        }
        return $.Deferred().resolve().promise();
    }
};

CollectionModel.prototype._hashTerms = function () {
    window.hex = createHash('sha256').update(this.get('terms'));
    return createHash('sha256').update(this.get('terms')).digest('base64');
};
<|endoftext|>


<commit_before>// adding nested resources with Cocoon through a UIkit.modal
Cmsify.NestedResources = function (el) {
  this.$el = $(el);
  this.$alertBox = this.$el.find('.js-alert-box');
  this.parsley = this.$el.closest('.js-parsley').parsley();
  this.$el.find('.js-nested-resource').each(function(index, el) {
    new Cmsify.NestedResource(el, {
      isNew: false,
      modelName: $(el).data('model-name'),
      parent: this,
      index: $(el).data('index')
    });
  }.bind(this));
  this.$el
    .on('cocoon:after-insert', function(e, insertedItem) {
       insertedItem.attr({
        "data-index" : insertedItem.parent().children().length - 1
      });
      new Cmsify.NestedResource(insertedItem, {
        isNew: true,
        modelName: insertedItem.data('model-name'),
        parent: this,
        index: insertedItem.data('index')
      });
    }.bind(this))
    .on('click', '.js-remove-association', function(e) {
      this.$alertBox.removeClass('uk-hidden');
      // TODO: If a user adds a new nested resource and presses cancel, the box still shows even though nothing new is there
    }.bind(this))
}

Cmsify.NestedResource = function(el, options) {
  this.$el = $(el);
  this.options = options;
  this.$doneButton = this.$el.find('.js-nested-resource__done');
  this.$cancelButton = this.$el.find('.js-nested-resource__cancel');
  this.$fields = this.$el.find(':input');
  this.parsleyGroup = this.options.modelName + this.options.index;
  this.modal = UIkit.modal(this.$el.find('.uk-modal'), {
    bgclose: false,
    center: true
  });
  this.boundHandleCloseClick = this.handleCloseClick.bind(this);
  this.isModified = false;
  this.init();

  this.modal.on('show.uk.modal', function() {
    this.lastData = this.serializeFields();
    sortable('.js-sortable', 'disable');
  }.bind(this));

  this.modal.on('hide.uk.modal', function() {
    sortable('.js-sortable', 'enable');
  }.bind(this));

  this.$doneButton
    .on('click', function(e) {
      e.preventDefault();
      if (this.validateFields()) {
        if (this.isModified) {
          this.updateResource();
          this.$el.addClass('uk-block-notification-light');
          this.options.parent.$alertBox.removeClass('uk-hidden');
        }
        this.modal.hide();
      }
    }.bind(this));

  this.$cancelButton
    .on('click', function(e) {
      e.preventDefault();
      this.modal.on('hide.uk.modal', this.boundHandleCloseClick);
      this.modal.hide();
    }.bind(this));

  this.$fields
    .on('keyup change blur', function(e) {
      this.validateFields();
    }.bind(this))
    .on('tinymce:change', function(e) {
      this.isModified = true;
    }.bind(this));
};

Cmsify.NestedResource.prototype.handleCloseClick = function() {
  if (this.options.isNew) {
    this.$el.find('.js-remove-association').trigger('click');
  } else {
    this.deserializeFields(this.lastData);
  }
  this.modal.off('hide.uk.modal', this.boundHandleCloseClick);
};

Cmsify.NestedResource.prototype.init = function() {
  if (this.options.isNew) { this.initNewResource(); }
  this.addValidationGroup();
};

Cmsify.NestedResource.prototype.validateFields = function() {
  var isValid = this.options.parent.parsley.validate({group: this.parsleyGroup});
  this.$doneButton.attr('disabled', !isValid);
  this.setIsModified();
  return isValid;
};

Cmsify.NestedResource.prototype.addValidationGroup = function() {
  this.$fields.each(function (index, el) {
     $(el).attr('data-parsley-group', this.parsleyGroup);
  }.bind(this));
};

Cmsify.NestedResource.prototype.initNewResource = function() {
  Cmsify.initTinymce();
  this.$el.addClass('uk-block-notification-light');
  this.$el.find('.js-move').html('');
  this.$el.find('.js-link').html('Adding New ' + this.options.modelName);
  this.modal.show();
};

Cmsify.NestedResource.prototype.getModalSelector = function() {
  return '.js-nested-resource[data-model-name="' + this.options.modelName + '"][data-index="' + this.options.index + '"] .uk-modal';
};

Cmsify.NestedResource.prototype.serializeFields = function () {
  //HACK needed because of how turbolinks is loading. Between the time that the page load
  //event is fired and the page actually becomes useful the authenicity token being changed
  //by turbolinks
  return Cmsify.util.filterAuthenticityToken(this.$el.find(':input').serializeArray());
};

Cmsify.NestedResource.prototype.deserializeFields = function(fields) {
  $.each(fields, function(key, value) {
    $('[name="'+ value['name'] +'"]').val(value['value']);
  });
};

Cmsify.NestedResource.prototype.setIsModified = function () {
  if (JSON.stringify(this.serializeFields()) != JSON.stringify(this.lastData)) {
    this.isModified = true;
  }
  return this.isModified;
};

Cmsify.NestedResource.prototype.updateResource = function() {
  this.options.isNew = false;
  var title = this.$el.find('.js-title').val();
  this.$el.find('.js-link').attr('href', this.getModalSelector()).html(title);
};
<commit_msg>Make ChangedFormModal compatible with tinyMCE<commit_after>// adding nested resources with Cocoon through a UIkit.modal
Cmsify.NestedResources = function (el) {
  this.$el = $(el);
  this.$alertBox = this.$el.find('.js-alert-box');
  this.parsley = this.$el.closest('.js-parsley').parsley();
  this.$el.find('.js-nested-resource').each(function(index, el) {
    new Cmsify.NestedResource(el, {
      isNew: false,
      modelName: $(el).data('model-name'),
      parent: this,
      index: $(el).data('index')
    });
  }.bind(this));
  this.$el
    .on('cocoon:after-insert', function(e, insertedItem) {
       insertedItem.attr({
        "data-index" : insertedItem.parent().children().length - 1
      });
      new Cmsify.NestedResource(insertedItem, {
        isNew: true,
        modelName: insertedItem.data('model-name'),
        parent: this,
        index: insertedItem.data('index')
      });
    }.bind(this))
    .on('click', '.js-remove-association', function(e) {
      this.$alertBox.removeClass('uk-hidden');
      // TODO: If a user adds a new nested resource and presses cancel, the box still shows even though nothing new is there
    }.bind(this))
}

Cmsify.NestedResource = function(el, options) {
  this.$el = $(el);
  this.options = options;
  this.$doneButton = this.$el.find('.js-nested-resource__done');
  this.$cancelButton = this.$el.find('.js-nested-resource__cancel');
  this.$fields = this.$el.find(':input');
  this.parsleyGroup = this.options.modelName + this.options.index;
  this.modal = UIkit.modal(this.$el.find('.uk-modal'), {
    bgclose: false,
    center: true
  });
  this.boundHandleCloseClick = this.handleCloseClick.bind(this);
  this.isModified = false;
  this.init();

  this.modal.on('show.uk.modal', function() {
    this.lastData = this.serializeFields();
    sortable('.js-sortable', 'disable');
  }.bind(this));

  this.modal.on('hide.uk.modal', function() {
    sortable('.js-sortable', 'enable');
  }.bind(this));

  this.$doneButton
    .on('click', function(e) {
      e.preventDefault();
      if (this.validateFields()) {
        if (this.isModified) {
          this.updateResource();
          this.$el.addClass('uk-block-notification-light');
          this.options.parent.$alertBox.removeClass('uk-hidden');
        }
        this.modal.hide();
      }
    }.bind(this));

  this.$cancelButton
    .on('click', function(e) {
      e.preventDefault();
      this.modal.on('hide.uk.modal', this.boundHandleCloseClick);
      this.modal.hide();
    }.bind(this));

  this.$fields
    .on('keyup change blur', function(e) {
      this.validateFields();
    }.bind(this))
    .on('tinymce:change', function(e) {
      this.isModified = true;
    }.bind(this));
};

Cmsify.NestedResource.prototype.handleCloseClick = function() {
  if (this.options.isNew) {
    this.$el.find('.js-remove-association').trigger('click');
  } else {
    this.deserializeFields(this.lastData);
  }
  this.modal.off('hide.uk.modal', this.boundHandleCloseClick);
};

Cmsify.NestedResource.prototype.init = function() {
  if (this.options.isNew) { this.initNewResource(); }
  this.addValidationGroup();
};

Cmsify.NestedResource.prototype.validateFields = function() {
  var isValid = this.options.parent.parsley.validate({group: this.parsleyGroup});
  this.$doneButton.attr('disabled', !isValid);
  this.setIsModified();
  return isValid;
};

Cmsify.NestedResource.prototype.addValidationGroup = function() {
  this.$fields.each(function (index, el) {
     $(el).attr('data-parsley-group', this.parsleyGroup);
  }.bind(this));
};

Cmsify.NestedResource.prototype.initNewResource = function() {
  Cmsify.initTinymce();
  this.$el.addClass('uk-block-notification-light');
  this.$el.find('.js-move').html('');
  this.$el.find('.js-link').html('Adding New ' + this.options.modelName);
  this.modal.show();
};

Cmsify.NestedResource.prototype.getModalSelector = function() {
  return '.js-nested-resource[data-model-name="' + this.options.modelName + '"][data-index="' + this.options.index + '"] .uk-modal';
};

Cmsify.NestedResource.prototype.serializeFields = function () {
  //HACK needed because of how turbolinks is loading. Between the time that the page load
  //event is fired and the page actually becomes useful the authenicity token being changed
  //by turbolinks
  return Cmsify.util.filterAuthenticityToken(this.$el.find(':input').serializeArray());
};

Cmsify.NestedResource.prototype.deserializeFields = function(fields) {
  $.each(fields, function(key, value) {
    $('[name="'+ value['name'] +'"]').val(value['value']);
  });
};

Cmsify.NestedResource.prototype.setIsModified = function () {
  if (tinyMCE.editors.some(function(editor) { return editor.isDirty() }) ||
      JSON.stringify(this.serializeFields()) != JSON.stringify(this.lastData)) {
    this.isModified = true;
  }
  return this.isModified;
};

Cmsify.NestedResource.prototype.updateResource = function() {
  this.options.isNew = false;
  var title = this.$el.find('.js-title').val();
  this.$el.find('.js-link').attr('href', this.getModalSelector()).html(title);
};
<|endoftext|>


<commit_before>var fs = require('fs');

//Constants & regexps -----

var regexpModule = new RegExp("angular.module\\(([A-Za-z0-9\"\\[\\]\', ]+)\\)","gm"),

    regexpModuleComponentSplit = new RegExp("\\.(service|directive|controller|factory|config)","g"),

    regexpModuleConfigs = new RegExp("\\.config\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),
    regexpModuleServices = new RegExp("\\.service\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),
    regexpModuleDirective = new RegExp("\\.directive\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),
    regexpModuleController = new RegExp("\\.controller\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),
    regexpModuleFactory = new RegExp("\\.factory\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),

    regexpTemplateUrl = /templateUrl:( ?)('|")([A-Za-z0-9.\/_-]+)('|")/,
    regexpTemplateUrls = /templateUrl:( ?)('|")([A-Za-z0-9.\/_-]+)('|")/g,
    regexpTemplate = /template:( ?)('|")(.+)('|"),/,
    regexpTemplates = /template:( ?)('|")(.+)('|"),/g,

    regexpCamelCase = /[A-Z]/g,
    regexpStrings = /('|")([A-Za-z0-9$]+)('|")/g,
    regexpNewLine = /(\n|\r)/g,
    regexpWrappers = /('|")/g,

    WARNING_MULTIPLE_REGISTRATION = 'multiple-registration',
    WARNING_MISSING_TEMPLATE_FILE = 'missing-template',
    WARNING_MISSING_DEPENDENCY = 'missing-dependency',
    WARNING_IGNORED_MODULE = 'ignored-module',
    WARNING_IGNORED_COMPONENT = 'ignored-component',
    WARNING_NOT_EXIST = 'not-exist',

    COMPONENT_SPLIT_ANCHOR = "---- CONTENT ANCHOR ----",

    COMPONENT_TYPE_CONFIG = ".config",
    COMPONENT_TYPE_SERVICE = ".service",
    COMPONENT_TYPE_CONTROLLER = ".controller",
    COMPONENT_TYPE_FACTORY = ".factory",
    COMPONENT_TYPE_DIRECTIVE = ".directive";

//Settings -----------------

var allowedWarningTypes = [
        WARNING_MULTIPLE_REGISTRATION,
        WARNING_MISSING_TEMPLATE_FILE,
        WARNING_MISSING_DEPENDENCY,
        WARNING_IGNORED_MODULE,
        WARNING_IGNORED_COMPONENT,
        WARNING_NOT_EXIST
    ],
    ignoredPaths = [],
    mainModule = '',
    mainHTML = '';

var argLen = process.argv.length,
    getParamValue = function(pos){
        if(pos >= argLen) return undefined;
        return process.argv[pos];
    };
for(var argId = 2; argId < argLen; argId++) {
    var paramName = process.argv[argId];
    switch(paramName) {
        case "--main-module":
            mainModule = getParamValue(++argId);
            break;
        case "--main-html":
            mainHTML = getParamValue(++argId);
            break;
        case "--ignore-path":
            ignoredPaths = getParamValue(++argId).split(",");
            break;
        case "--ignore-warning":
            var ignored = getParamValue(++argId).split(",");
            allowedWarningTypes = allowedWarningTypes.filter(function(warningType){
                return ignored.indexOf(warningType) == -1;
            });
            break;
        default:
            console.warn("Unknown parameter '" + paramName + "'");
            break;
    }
}

if(!mainModule || mainModule == "") {
    console.warn("Main module is not set. You cannot map dependencies without setting main module (use --main-module <module name>)");
    return;
}

if(!mainHTML || mainHTML == "") {
    console.warn("Main HTML file is not set. You cannot map dependencies without setting main HTML file (use --main-html <filename>)");
    return;
}

//Types --------------------

/**
 * Creates module with dependencies
 * @param {string} name
 * @param {string} filename
 * @param {Array} dependencies
 * @constructor
 */
var Module = function(name,filename,dependencies){
    this.name = name;
    this.filename = filename;
    this.dependencies = dependencies;
    this.components = {};
    this.processed = false;
    this.included = false;
};
Module.prototype.addComponent = function(component){
    if(this.components.hasOwnProperty(component.name)) {
        postWarning(WARNING_MULTIPLE_REGISTRATION, this, " is registering component '" + component.name + "' multiple times");
    }
    this.components[component.name] = component;
};
Module.prototype.isUsed = function(){
    return this.included;
};
Module.prototype.markAsUsed = function(){
    this.included = true;
};

/**
 * Creates component with dependencies
 * @param {string} name
 * @param {string} type
 * @param {Module} module
 * @param {Array} dependencies
 * @param {string=} source
 * @constructor
 */
var Component = function(name,type,module,dependencies,source){
    this.name = name;
    this.type = type;
    this.module = module;
    this.dependencies = dependencies;
    this.source = source || "";
    this.included = false;

    if(this.type == COMPONENT_TYPE_DIRECTIVE) {
        this.directiveName = deCamelCase(this.name);
    }
};
Component.prototype.getName = function(){
    return this.name;
};
Component.prototype.isUsed = function(){
    return this.included;
};
Component.prototype.markAsUsed = function(){
    this.included = true;
};

//Helper functions --------------

/**
 * Returns content of string's string
 * @param {string} str
 * @returns {string}
 */
function captureContent(str){
    var len = str.length,
        i,
        start = 0,
        currentChar = "",
        prevChar = "",
        contentChar = "";

    for(i = 0; i < len; i++) {
        currentChar = str[i];
        if(contentChar == "" && (currentChar == "'" || currentChar == '"')) {
            contentChar = currentChar;
            start = i;
        } else if(currentChar == contentChar && prevChar != "\\") {
            return str.substr(start,i);
        }
        prevChar = str[i];
    }
    return "";
}

/**
 * Create directive-like string from camelCase
 * @param {string} str
 * @returns {string}
 */
function deCamelCase(str){
    return str.replace(regexpCamelCase,function(letter,pos){
        return (pos == 0 ? letter : "-" + letter).toLowerCase();
    });
}

/**
 * Prints warning to console (+ checks for warning type and ignores)
 * @param {string} type
 * @param {Module} module
 * @param {string} str
 */
function postWarning(type, module, str){
    if(allowedWarningTypes.indexOf(type) > -1) {
        //console.warn(module.filename + ": Module '" + module.name + "'" + str);
        console.warn("Module '" + module.name + "'" + str);
    }
}

/**
 * Returns list of files found in folder & subfolders
 * @param {string} path
 * @param {string} suffix
 * @returns {Array}
 */
function readFolder(path, suffix) {
    var list = [];
    fs.readdirSync(path).forEach(function (fileOrDir) {
        var stat = fs.lstatSync(path + "/" + fileOrDir);
        if (stat.isFile() && fileOrDir.indexOf("."+suffix) == fileOrDir.length - (suffix.length +1)) {
            list.push(path + "/" + fileOrDir);

        } else if (stat.isDirectory() && path != "src/styleguide" && path != "src/assets") {
            list = list.concat(readFolder(path + "/" + fileOrDir,suffix));
        }
    });
    return list;
}

/**
 * Remove " & ' from string
 * @param {string} str
 * @returns {string}
 */
function removeWrappers(str){
    return str.replace(regexpWrappers,"");
}

/**
 * Returns object with module name and array of dependencies
 * @param {string} moduleHeader
 * @param {string} filepath
 * @returns {Module}
 */
function getModuleInfo(moduleHeader,filepath) {
    var moduleName = "",
        dependencies = moduleHeader.match(regexpStrings);

    if (dependencies && dependencies.length > 0) {
        dependencies = dependencies.map(removeWrappers);
        moduleName = dependencies[0];
        dependencies = dependencies.filter(function (item) {
            return item != moduleName;
        });

    } else {
        moduleName = removeWrappers(moduleHeader);
        dependencies = [];
    }

    return new Module(moduleName,filepath,dependencies);
}

//Workflow -----------------
var allModules = {},
    allComponents = {},
    allDirectives = {},
    ignoredDependencies = ["ngRoute","ngAnimate"],
    ignoredComponents = ["$q","$window","$location","$scope","$rootScope","$http","$timeout","$routeParams","$routeProvider","$animate","$compile","$controller","$filter","$sce"];

var componentName,
    moduleName;

var registerComponent = function(name,module,component){
    if(allComponents.hasOwnProperty(name)) {
        postWarning(WARNING_MULTIPLE_REGISTRATION, module, " is registering component '" + component.getName() + "' which is already registered");
    }
    allComponents[name] = component;
    module.addComponent(component);
};

//1) Read source files
var sourceFiles = readFolder("./","js").filter(function(item){
    for(var p = 0; p < ignoredPaths.length; p++) if(item.indexOf(ignoredPaths[p]) == 0) return false;
    return true;
});

//2) Go trough each source file and read module name & dependencies
//[sourceFiles[5]].forEach(function(filepath){
sourceFiles.forEach(function(filepath){
    var fullContent = fs.readFileSync(filepath).toString().replace(regexpNewLine,"");
    var moduleName = "";

    var separateModuleContents = fullContent.split("angular.module");
    separateModuleContents.forEach(function(content){
        var module;

        //Read module name & dependencies
        var modulesMatch = ("angular.module" + content).match(regexpModule);
        if(modulesMatch && modulesMatch.length > 0) {
            module = getModuleInfo(modulesMatch[0],filepath);
            module.file = filepath;
            module.included = false;
            allModules[module.name] = module;
            moduleName = module.name;
        } else {
            //Skip reading controllers etc. from module as there is no module :)
            return
        }

        var components = content.replace(regexpModuleComponentSplit,COMPONENT_SPLIT_ANCHOR + " .$1").split(COMPONENT_SPLIT_ANCHOR),
            i,
            len = components.length,
            componentName;

        for(i = 1; i < len; i++) {
            var component = components[i];

            //Read module configs
            var configsMatch = component.match(regexpModuleConfigs);
            if(configsMatch && configsMatch.length > 0) {
                var configs = configsMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = module.name+".config";
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_CONFIG,module,configs,component));
                continue;
            }

            //Read module services
            var servicesMatch = component.match(regexpModuleServices);
            if(servicesMatch && servicesMatch.length > 0) {
                var services = servicesMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = services[0];
                services = services.slice(1);
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_SERVICE,module,services,component));
                continue;
            }

            //Read module directives
            var directivesMatch = component.match(regexpModuleDirective);
            if(directivesMatch && directivesMatch.length > 0) {
                var directives = directivesMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = directives[0];
                directives = directives.slice(1);
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_DIRECTIVE,module,directives,component));
                continue;
            }

            //Read module controllers
            var controllersMatch = component.match(regexpModuleController);
            if(controllersMatch && controllersMatch.length > 0) {
                var controllers = controllersMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = controllers[0];
                controllers = controllers.slice(1);
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_CONTROLLER,module,controllers,component));
                continue;
            }

            //Read module factories
            var factoriesMatch = component.match(regexpModuleFactory);
            if(factoriesMatch && factoriesMatch.length > 0) {
                var factories = factoriesMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = factories[0];
                factories = factories.slice(1);
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_FACTORY,module,factories,component));
            }
        }

    });
});

//3) Read directive names from components
for(componentName in allComponents) if(allComponents.hasOwnProperty(componentName) && allComponents[componentName].type == COMPONENT_TYPE_DIRECTIVE) {
    var directive = allComponents[componentName];
    allDirectives[directive.directiveName] = directive;
}

//4) Check basic module & its dependencies
var markDependenciesFromHtml = function(html){
    for(var directiveName in allDirectives) if(allDirectives.hasOwnProperty(directiveName) && html.indexOf(directiveName) > -1) {
        allDirectives[directiveName].markAsUsed();
    }
};

var markDependencies = function(moduleName){
    //Check for existence
    if(!allModules.hasOwnProperty(moduleName)) {
        console.warn("Referenced module '" + moduleName + "' does not exist!");
        return
    }

    //Read module
    var module = allModules[moduleName];

    //Check if it has been processed
    if(module.processed) {
        return;
    }

    //Mark module as included
    module.markAsUsed();
    module.processed = true;

    //Go trough dependencies
    module.dependencies.forEach(function(dependency){
        if(ignoredDependencies.indexOf(dependency) == -1) {
            markDependencies(dependency);
        }
    });

    //Go trough components
    for(var componentName in module.components) if(module.components.hasOwnProperty(componentName)) {
        var component = module.components[componentName];
        component.dependencies.forEach(function(dependencyName){
            if(ignoredComponents.indexOf(dependencyName) == -1) {
                if(!allComponents.hasOwnProperty(dependencyName)) {
                    postWarning(WARNING_NOT_EXIST,module," > '" + component.getName() + "' is referencing '" + dependencyName + "' which does not exist!");
                } else {
                    var dependency = allComponents[dependencyName];
                    dependency.markAsUsed();
                    if(module.name != dependency.module.name && module.dependencies.indexOf(dependency.module.name) == -1) {
                        postWarning(WARNING_MISSING_DEPENDENCY,module," > '" + component.getName() + "' referenced component '" + dependencyName + "' but it's missing module depencency '" + dependency.module.name + "'!");
                    }
                }
            }
        });

        //If components is config -> Check templates
        //TODO: Check templates in configs

        //If component is directive -> Check template contents for directives (if template is present)
        if(component.type == COMPONENT_TYPE_DIRECTIVE) {
            //Check for templateUrl
            var templateUrl = component.source.match(regexpTemplateUrl);
            if(templateUrl && templateUrl.length > 3) {
                markDependenciesFromHtml(fs.readFileSync(templateUrl[3]).toString());
                continue;
            }

            //Check for template
            var template = component.source.match(regexpTemplate);
            if(template && template.length > 3) {
                markDependenciesFromHtml(captureContent(template[0]));
                continue;
            }
        }
    }
};
markDependenciesFromHtml(fs.readFileSync(mainHTML).toString());
markDependencies(mainModule);

//3) Check dependencies & mark as included
for(moduleName in allModules) if(allModules.hasOwnProperty(moduleName)) {
    var module = allModules[moduleName];
    if(!module.isUsed()) postWarning(WARNING_IGNORED_MODULE, module, " is not used");
}
for(componentName in allComponents) if(allComponents.hasOwnProperty(componentName)) {
    var component = allComponents[componentName];
    if(!component.isUsed() && component.module.isUsed() && component.type == COMPONENT_TYPE_DIRECTIVE) postWarning(WARNING_IGNORED_COMPONENT, component.module, " > '" + component.getName() + "' is not used");
}

<commit_msg>++warning counts<commit_after>var fs = require('fs');

//Variables ---------------
var warningsLogged = 0,
    warningsSkipped = 0;

//Constants & regexps -----

var regexpModule = new RegExp("angular.module\\(([A-Za-z0-9\"\\[\\]\', ]+)\\)","gm"),

    regexpModuleComponentSplit = new RegExp("\\.(service|directive|controller|factory|config)","g"),

    regexpModuleConfigs = new RegExp("\\.config\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),
    regexpModuleServices = new RegExp("\\.service\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),
    regexpModuleDirective = new RegExp("\\.directive\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),
    regexpModuleController = new RegExp("\\.controller\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),
    regexpModuleFactory = new RegExp("\\.factory\\(([A-Za-z0-9$\"\\[\\]\', ]+)(\\s?)fun","gm"),

    regexpTemplateUrl = /templateUrl:( ?)('|")([A-Za-z0-9.\/_-]+)('|")/,
    regexpTemplateUrls = /templateUrl:( ?)('|")([A-Za-z0-9.\/_-]+)('|")/g,
    regexpTemplate = /template:( ?)('|")(.+)('|"),/,
    regexpTemplates = /template:( ?)('|")(.+)('|"),/g,

    regexpCamelCase = /[A-Z]/g,
    regexpStrings = /('|")([A-Za-z0-9$]+)('|")/g,
    regexpNewLine = /(\n|\r)/g,
    regexpWrappers = /('|")/g,

    WARNING_MULTIPLE_REGISTRATION = 'multiple-registration',
    WARNING_MISSING_TEMPLATE_FILE = 'missing-template',
    WARNING_MISSING_DEPENDENCY = 'missing-dependency',
    WARNING_IGNORED_MODULE = 'ignored-module',
    WARNING_IGNORED_COMPONENT = 'ignored-component',
    WARNING_NOT_EXIST = 'not-exist',

    COMPONENT_SPLIT_ANCHOR = "---- CONTENT ANCHOR ----",

    COMPONENT_TYPE_CONFIG = ".config",
    COMPONENT_TYPE_SERVICE = ".service",
    COMPONENT_TYPE_CONTROLLER = ".controller",
    COMPONENT_TYPE_FACTORY = ".factory",
    COMPONENT_TYPE_DIRECTIVE = ".directive";

//Settings -----------------

var allowedWarningTypes = [
        WARNING_MULTIPLE_REGISTRATION,
        WARNING_MISSING_TEMPLATE_FILE,
        WARNING_MISSING_DEPENDENCY,
        WARNING_IGNORED_MODULE,
        WARNING_IGNORED_COMPONENT,
        WARNING_NOT_EXIST
    ],
    ignoredPaths = [],
    mainModule = '',
    mainHTML = '';

var argLen = process.argv.length,
    getParamValue = function(pos){
        if(pos >= argLen) return undefined;
        return process.argv[pos];
    };
for(var argId = 2; argId < argLen; argId++) {
    var paramName = process.argv[argId];
    switch(paramName) {
        case "--main-module":
            mainModule = getParamValue(++argId);
            break;
        case "--main-html":
            mainHTML = getParamValue(++argId);
            break;
        case "--ignore-path":
            ignoredPaths = getParamValue(++argId).split(",");
            break;
        case "--ignore-warning":
            var ignored = getParamValue(++argId).split(",");
            allowedWarningTypes = allowedWarningTypes.filter(function(warningType){
                return ignored.indexOf(warningType) == -1;
            });
            break;
        default:
            console.warn("Unknown parameter '" + paramName + "'");
            break;
    }
}

if(!mainModule || mainModule == "") {
    console.warn("Main module is not set. You cannot map dependencies without setting main module (use --main-module <module name>)");
    return;
}

if(!mainHTML || mainHTML == "") {
    console.warn("Main HTML file is not set. You cannot map dependencies without setting main HTML file (use --main-html <filename>)");
    return;
}

//Types --------------------

/**
 * Creates module with dependencies
 * @param {string} name
 * @param {string} filename
 * @param {Array} dependencies
 * @constructor
 */
var Module = function(name,filename,dependencies){
    this.name = name;
    this.filename = filename;
    this.dependencies = dependencies;
    this.components = {};
    this.processed = false;
    this.included = false;
};
Module.prototype.addComponent = function(component){
    if(this.components.hasOwnProperty(component.name)) {
        postWarning(WARNING_MULTIPLE_REGISTRATION, this, " is registering component '" + component.name + "' multiple times");
    }
    this.components[component.name] = component;
};
Module.prototype.isUsed = function(){
    return this.included;
};
Module.prototype.markAsUsed = function(){
    this.included = true;
};

/**
 * Creates component with dependencies
 * @param {string} name
 * @param {string} type
 * @param {Module} module
 * @param {Array} dependencies
 * @param {string=} source
 * @constructor
 */
var Component = function(name,type,module,dependencies,source){
    this.name = name;
    this.type = type;
    this.module = module;
    this.dependencies = dependencies;
    this.source = source || "";
    this.included = false;

    if(this.type == COMPONENT_TYPE_DIRECTIVE) {
        this.directiveName = deCamelCase(this.name);
    }
};
Component.prototype.getName = function(){
    return this.name;
};
Component.prototype.isUsed = function(){
    return this.included;
};
Component.prototype.markAsUsed = function(){
    this.included = true;
};

//Helper functions --------------

/**
 * Returns content of string's string
 * @param {string} str
 * @returns {string}
 */
function captureContent(str){
    var len = str.length,
        i,
        start = 0,
        currentChar = "",
        prevChar = "",
        contentChar = "";

    for(i = 0; i < len; i++) {
        currentChar = str[i];
        if(contentChar == "" && (currentChar == "'" || currentChar == '"')) {
            contentChar = currentChar;
            start = i;
        } else if(currentChar == contentChar && prevChar != "\\") {
            return str.substr(start,i);
        }
        prevChar = str[i];
    }
    return "";
}

/**
 * Create directive-like string from camelCase
 * @param {string} str
 * @returns {string}
 */
function deCamelCase(str){
    return str.replace(regexpCamelCase,function(letter,pos){
        return (pos == 0 ? letter : "-" + letter).toLowerCase();
    });
}

/**
 * Prints warning to console (+ checks for warning type and ignores)
 * @param {string} type
 * @param {Module} module
 * @param {string} str
 */
function postWarning(type, module, str){
    if(allowedWarningTypes.indexOf(type) > -1) {
        //console.warn(module.filename + ": Module '" + module.name + "'" + str);
        console.warn("Module '" + module.name + "'" + str);
        warningsLogged++;
    } else {
        warningsSkipped++;
    }
}

/**
 * Returns list of files found in folder & subfolders
 * @param {string} path
 * @param {string} suffix
 * @returns {Array}
 */
function readFolder(path, suffix) {
    var list = [];
    fs.readdirSync(path).forEach(function (fileOrDir) {
        var stat = fs.lstatSync(path + "/" + fileOrDir);
        if (stat.isFile() && fileOrDir.indexOf("."+suffix) == fileOrDir.length - (suffix.length +1)) {
            list.push(path + "/" + fileOrDir);

        } else if (stat.isDirectory() && path != "src/styleguide" && path != "src/assets") {
            list = list.concat(readFolder(path + "/" + fileOrDir,suffix));
        }
    });
    return list;
}

/**
 * Remove " & ' from string
 * @param {string} str
 * @returns {string}
 */
function removeWrappers(str){
    return str.replace(regexpWrappers,"");
}

/**
 * Returns object with module name and array of dependencies
 * @param {string} moduleHeader
 * @param {string} filepath
 * @returns {Module}
 */
function getModuleInfo(moduleHeader,filepath) {
    var moduleName = "",
        dependencies = moduleHeader.match(regexpStrings);

    if (dependencies && dependencies.length > 0) {
        dependencies = dependencies.map(removeWrappers);
        moduleName = dependencies[0];
        dependencies = dependencies.filter(function (item) {
            return item != moduleName;
        });

    } else {
        moduleName = removeWrappers(moduleHeader);
        dependencies = [];
    }

    return new Module(moduleName,filepath,dependencies);
}

//Workflow -----------------
var allModules = {},
    allComponents = {},
    allDirectives = {},
    ignoredDependencies = ["ngRoute","ngAnimate"],
    ignoredComponents = ["$q","$window","$location","$scope","$rootScope","$http","$timeout","$routeParams","$routeProvider","$animate","$compile","$controller","$filter","$sce"];

var componentName,
    moduleName;

var registerComponent = function(name,module,component){
    if(allComponents.hasOwnProperty(name)) {
        postWarning(WARNING_MULTIPLE_REGISTRATION, module, " is registering component '" + component.getName() + "' which is already registered");
    }
    allComponents[name] = component;
    module.addComponent(component);
};

//1) Read source files
var sourceFiles = readFolder("./","js").filter(function(item){
    for(var p = 0; p < ignoredPaths.length; p++) if(item.indexOf(ignoredPaths[p]) == 0) return false;
    return true;
});

//2) Go trough each source file and read module name & dependencies
//[sourceFiles[5]].forEach(function(filepath){
sourceFiles.forEach(function(filepath){
    var fullContent = fs.readFileSync(filepath).toString().replace(regexpNewLine,"");
    var moduleName = "";

    var separateModuleContents = fullContent.split("angular.module");
    separateModuleContents.forEach(function(content){
        var module;

        //Read module name & dependencies
        var modulesMatch = ("angular.module" + content).match(regexpModule);
        if(modulesMatch && modulesMatch.length > 0) {
            module = getModuleInfo(modulesMatch[0],filepath);
            module.file = filepath;
            module.included = false;
            allModules[module.name] = module;
            moduleName = module.name;
        } else {
            //Skip reading controllers etc. from module as there is no module :)
            return
        }

        var components = content.replace(regexpModuleComponentSplit,COMPONENT_SPLIT_ANCHOR + " .$1").split(COMPONENT_SPLIT_ANCHOR),
            i,
            len = components.length,
            componentName;

        for(i = 1; i < len; i++) {
            var component = components[i];

            //Read module configs
            var configsMatch = component.match(regexpModuleConfigs);
            if(configsMatch && configsMatch.length > 0) {
                var configs = configsMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = module.name+".config";
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_CONFIG,module,configs,component));
                continue;
            }

            //Read module services
            var servicesMatch = component.match(regexpModuleServices);
            if(servicesMatch && servicesMatch.length > 0) {
                var services = servicesMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = services[0];
                services = services.slice(1);
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_SERVICE,module,services,component));
                continue;
            }

            //Read module directives
            var directivesMatch = component.match(regexpModuleDirective);
            if(directivesMatch && directivesMatch.length > 0) {
                var directives = directivesMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = directives[0];
                directives = directives.slice(1);
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_DIRECTIVE,module,directives,component));
                continue;
            }

            //Read module controllers
            var controllersMatch = component.match(regexpModuleController);
            if(controllersMatch && controllersMatch.length > 0) {
                var controllers = controllersMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = controllers[0];
                controllers = controllers.slice(1);
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_CONTROLLER,module,controllers,component));
                continue;
            }

            //Read module factories
            var factoriesMatch = component.match(regexpModuleFactory);
            if(factoriesMatch && factoriesMatch.length > 0) {
                var factories = factoriesMatch[0].match(regexpStrings).map(removeWrappers);
                componentName = factories[0];
                factories = factories.slice(1);
                registerComponent(componentName, module, new Component(componentName,COMPONENT_TYPE_FACTORY,module,factories,component));
            }
        }

    });
});

//3) Read directive names from components
for(componentName in allComponents) if(allComponents.hasOwnProperty(componentName) && allComponents[componentName].type == COMPONENT_TYPE_DIRECTIVE) {
    var directive = allComponents[componentName];
    allDirectives[directive.directiveName] = directive;
}

//4) Check basic module & its dependencies
var markDependenciesFromHtml = function(html){
    for(var directiveName in allDirectives) if(allDirectives.hasOwnProperty(directiveName) && html.indexOf(directiveName) > -1) {
        allDirectives[directiveName].markAsUsed();
    }
};

var markDependencies = function(moduleName){
    //Check for existence
    if(!allModules.hasOwnProperty(moduleName)) {
        console.warn("Referenced module '" + moduleName + "' does not exist!");
        return
    }

    //Read module
    var module = allModules[moduleName];

    //Check if it has been processed
    if(module.processed) {
        return;
    }

    //Mark module as included
    module.markAsUsed();
    module.processed = true;

    //Go trough dependencies
    module.dependencies.forEach(function(dependency){
        if(ignoredDependencies.indexOf(dependency) == -1) {
            markDependencies(dependency);
        }
    });

    //Go trough components
    for(var componentName in module.components) if(module.components.hasOwnProperty(componentName)) {
        var component = module.components[componentName];
        component.dependencies.forEach(function(dependencyName){
            if(ignoredComponents.indexOf(dependencyName) == -1) {
                if(!allComponents.hasOwnProperty(dependencyName)) {
                    postWarning(WARNING_NOT_EXIST,module," > '" + component.getName() + "' is referencing '" + dependencyName + "' which does not exist!");
                } else {
                    var dependency = allComponents[dependencyName];
                    dependency.markAsUsed();
                    if(module.name != dependency.module.name && module.dependencies.indexOf(dependency.module.name) == -1) {
                        postWarning(WARNING_MISSING_DEPENDENCY,module," > '" + component.getName() + "' referenced component '" + dependencyName + "' but it's missing module depencency '" + dependency.module.name + "'!");
                    }
                }
            }
        });

        //If components is config -> Check templates
        //TODO: Check templates in configs

        //If component is directive -> Check template contents for directives (if template is present)
        if(component.type == COMPONENT_TYPE_DIRECTIVE) {
            //Check for templateUrl
            var templateUrl = component.source.match(regexpTemplateUrl);
            if(templateUrl && templateUrl.length > 3) {
                markDependenciesFromHtml(fs.readFileSync(templateUrl[3]).toString());
                continue;
            }

            //Check for template
            var template = component.source.match(regexpTemplate);
            if(template && template.length > 3) {
                markDependenciesFromHtml(captureContent(template[0]));
                continue;
            }
        }
    }
};
markDependenciesFromHtml(fs.readFileSync(mainHTML).toString());
markDependencies(mainModule);

//3) Check dependencies & mark as included
for(moduleName in allModules) if(allModules.hasOwnProperty(moduleName)) {
    var module = allModules[moduleName];
    if(!module.isUsed()) postWarning(WARNING_IGNORED_MODULE, module, " is not used");
}
for(componentName in allComponents) if(allComponents.hasOwnProperty(componentName)) {
    var component = allComponents[componentName];
    if(!component.isUsed() && component.module.isUsed() && component.type == COMPONENT_TYPE_DIRECTIVE) postWarning(WARNING_IGNORED_COMPONENT, component.module, " > '" + component.getName() + "' is not used");
}

console.warn("---------------------------");
console.warn(warningsLogged + " visible warnings");
console.warn(warningsSkipped + " silent warnings");
console.warn((warningsLogged + warningsSkipped) + " warnings at total");
<|endoftext|>


<commit_before>var express = require('express');
var app = express.createServer();
var redis = require('redis');
var client = redis.createClient();
var color = require('../lib/colors');
var admin_config = require('./admin_config');
var weblistener_config = require('./weblistener_config');

client.publish('out', JSON.stringify({
    channel: admin_config.channel,
    message: 'web listener online',
}));

app.use(express.bodyParser());

app.post('/:app', function(req, res) {
    message = {
	app: req.params['app'],
	body: req.body
    };
    client.publish('web_in', JSON.stringify(message));
    res.send('',404)
});

app.listen(weblistener_config.port);
<commit_msg>little more logging<commit_after>var express = require('express');
var app = express.createServer();
var redis = require('redis');
var client = redis.createClient();
var color = require('../lib/colors');
var admin_config = require('./admin_config');
var weblistener_config = require('./weblistener_config');

client.publish('out', JSON.stringify({
    channel: admin_config.channel,
    message: 'web listener online',
}));

app.use(express.bodyParser());

app.post('/:app', function(req, res) {
    console.log(req.params['app']);
    message = {
	app: req.params['app'],
	body: req.body
    };
    client.publish('web_in', JSON.stringify(message));
    res.send('',404)
});

app.listen(weblistener_config.port);
<|endoftext|>