<commit_before>jQuery(document).ready(function() {

    $.extend( $.ui.autocomplete.prototype, {

    	_renderItem: function( ul, item) {
        return $( "

" )
          .data( "item.autocomplete", item )
          .append( $( "" ).html( item.html || item.label ) )
          .appendTo( ul );
      }
    });

    //hide instructions
     $('#search_hint').hide();

    //search hint
    $('#main_autocomplete').blur(
      function(){
        $('#main_autocomplete').val("I'm looking for...");
        $('#search_hint').hide();
      }
    );

    $('#main_autocomplete').focus(
      function(){
        $('#main_autocomplete').val("");
        $('#search_hint').show();
      }
    );

    $("#main_autocomplete").autocomplete({
        delay: 0,
        source: function( request, response ) {
          $.ajax({
            url: "/search/autocomplete",
            dataType: "jsonp",
            data: {
              term: request.term
            },
            success: function( data ) {
              var highlight_term = function(string,term) {
                html_safe = html_escape(string);
                var terms = term.split(' ');
                for (var i in terms)  {
                  var clean_term = html_escape(terms[i].replace(/^\s+|\s+$/g, ''));
                  if (clean_term != "") {
                    var regex = new RegExp("("+clean_term+")","ig");
                    html_safe = html_safe.replace(regex,'$1');
                  }
                }
                return html_safe;
              };
              var filter = function(search_term,data) {
                return $.map(data, function(item) {
                  return {
                    label: html_escape(item.label),
                    html:  highlight_term(item.label,search_term),
                    url:   item.url
                  }
                });
              };
              var html_escape = function( string) {
                return $('
').text(string).html();
              }
              var search_term = request.term;
						  last_item = {
                label: "search the site for "+html_escape(search_term),
                html:  "search the site for "+html_escape(search_term)+"",
                url:   "/search?q="+encodeURIComponent(search_term)
              };
              data = filter(search_term,data.slice(0,10));
              data.push(last_item);
              response( data );
            }
          });
        },
        select: function(event, ui) {
          location.href = ui.item.url
        },
        open: function(event, ui){
          // console.debug(event);
        }
    });

});
<commit_msg>Append a query string to every option in the search box<commit_after>jQuery(document).ready(function() {

    $.extend( $.ui.autocomplete.prototype, {

    	_renderItem: function( ul, item) {
        return $( "

" )
          .data( "item.autocomplete", item )
          .append( $( "" ).html( item.html || item.label ) )
          .appendTo( ul );
      }
    });

    //hide instructions
     $('#search_hint').hide();

    //search hint
    $('#main_autocomplete').blur(
      function(){
        $('#main_autocomplete').val("I'm looking for...");
        $('#search_hint').hide();
      }
    );

    $('#main_autocomplete').focus(
      function(){
        $('#main_autocomplete').val("");
        $('#search_hint').show();
      }
    );

    $("#main_autocomplete").autocomplete({
        delay: 0,
        source: function( request, response ) {
          $.ajax({
            url: "/search/autocomplete",
            dataType: "jsonp",
            data: {
              term: request.term
            },
            success: function( data ) {
              var highlight_term = function(string,term) {
                html_safe = html_escape(string);
                var terms = term.split(' ');
                for (var i in terms)  {
                  var clean_term = html_escape(terms[i].replace(/^\s+|\s+$/g, ''));
                  if (clean_term != "") {
                    var regex = new RegExp("("+clean_term+")","ig");
                    html_safe = html_safe.replace(regex,'$1');
                  }
                }
                return html_safe;
              };
              var filter = function(search_term,data) {
                return $.map(data, function(item) {
                  return {
                    label: html_escape(item.label),
                    html:  highlight_term(item.label,search_term),
                    url:   item.url + "?q=" + encodeURIComponent(item.label)
                  }
                });
              };
              var html_escape = function( string) {
                return $('
').text(string).html();
              }
              var search_term = request.term;
						  last_item = {
                label: "search the site for "+html_escape(search_term),
                html:  "search the site for "+html_escape(search_term)+"",
                url:   "/search?q="+encodeURIComponent(search_term)
              };
              data = filter(search_term,data.slice(0,10));
              data.push(last_item);
              response( data );
            }
          });
        },
        select: function(event, ui) {
          location.href = ui.item.url
        },
        open: function(event, ui){
          // console.debug(event);
        }
    });

});
<|endoftext|>


<commit_before>/**
 * @overview ccm component for fill-in-the-blank texts
 * @author André Kless <andre.kless@web.de> 2017
 * @license The MIT License (MIT)
 */

( function () {

  var ccm_version = '8.0.0';
  var ccm_url     = '../../ccm-developer/ccm/ccm.js';

  var component_name = 'cloze';
  var component_obj  = {

    name: component_name,

    config: {

      text: 'Hello, [[(W)o(rl)d]]!',
      html_templates: {
        main: {
          id: 'main',
          inner: {
            tag: 'form',
            id: 'form',
            inner: [
              { id: 'keywords' },
              { id: 'text' },
              { id: 'button' },
              { id: 'timer' }
            ],
            onsubmit: '%%'
          }
        },
        keyword: {
          class: 'keyword',
          inner: '%%'
        },
        button: {
          tag: 'input',
          type: 'submit',
          value: '%caption%'
        },
        timer: {
          tag: 'span',
          inner: '%%'
        }
      },
      css_layout: [ 'ccm.load', '../cloze/layouts/default.css' ]

  //  blank: true,
  //  ignore_case: true,
  //  keywords: [ 'keyword1', 'keyword2', ... ],
  //  points_per_gap: 1,
  //  time: 60,
  //  button_caption: 'finish',
  //  user: [ 'ccm.instance', '../user/ccm.user.js' ],
  //  logger: [ 'ccm.instance', '../log/ccm.log.js', [ ccm.get, '../log/configs.json', 'greedy' ] ],
  //  onchange: function ( instance, data ) { console.log( data ); },
  //  oninput: function ( instance, data ) { console.log( data ); },
  //  onfinish: function ( instance, results ) { console.log( results ); }

    },

    Instance: function () {

      var self = this;
      var my;             // contains privatized instance members
      var keywords = [];  // information data for each keyword

      this.init = function ( callback ) {

        // fill-in-the-blank text is given via inner HTML? => use it with higher priority
        if ( self.node && self.node.innerHTML.trim() ) self.text = self.node.innerHTML;

        callback();
      };

      this.ready = function ( callback ) {

        // privatize all possible instance members
        my = self.ccm.helper.privatize( self );

        var regex_keyword = /\[\[.+?\]\]/g;   // regular expression for finding all gaps/keywords in the text
        var regex_given = /\(.+?\)/g;         // regular expression for finding all given characters of a keyword

        // iterate all keywords in the text to determine the information data for each keyword
        ( my.text.match( regex_keyword ) || [] ).map( function ( keyword ) {

          // remove distinguishing characteristic '[[' and ']]'
          keyword = keyword.substr( 2, keyword.length - 4 );

          // replace all given characters of a keywords with '*'
          var keyw__d = keyword.replace( '*', '#' ).replace( regex_given, function ( given ) {
            var length = given.length - 2;
            given = '';
            for ( var i = 0; i < length; i++ ) given += '*';
            return given;
          } );

          // determine given characters and hold this information in a single number (disadvantage: possible positions
          var givens = 0;                                                      // for given letters in a word are 0-31
          for ( var i = 0; i < keyw__d.length; i++ )                           // because of data type limitations)
            if ( keyw__d.charAt( i ) === '*' ) givens += Math.pow( 2, i );

          // add keyword information data for current keyword
          keywords.push( {
            word: keyword.replace( regex_given, function ( given ) { return given.substr( 1, given.length - 2 ); } ),
            givens: givens
          } );

        } );

        // replace gaps/keywords with empty span elements
        my.text = my.text.replace( regex_keyword, '' );

        callback();
      };

      this.start = function ( callback ) {

        // initial result data
        var results = { points: 0, max_points: 0, details: [] };

        // prepare main HTML structure
        var main_elem = self.ccm.helper.html( my.html_templates.main, onFinish );

        var   text_elem  = main_elem.querySelector( '#text'   );  // container for text with containing gaps
        var button_elem  = main_elem.querySelector( '#button' );  // container for finish button
        var  timer_elem  = main_elem.querySelector( '#timer'  );  // container for timer
        var  timer_value = my.time;                               // timer value

        // add content for inner containers
        renderKeywords();
        renderText();
        renderButton();
        if ( my.time ) renderTimer(); else self.ccm.helper.removeElement( timer_elem );

        // remember start time
        var time = new Date().getTime();

        // set content of own website area
        self.ccm.helper.setContent( self.element, self.ccm.helper.protect( main_elem ) );

        // has logger instance? => log start event
        if ( self.logger ) self.logger.log( 'start', my );

        if ( callback ) callback();

        /**
         * @summary renders given keywords for text gaps
         * @description
         * Keywords could be given (individual) via instance configuration (my.keywords is string array)
         * or (automatic generated) via private variable 'keywords' (my.keywords is boolean true).
         */
        function renderKeywords() {

          var keywords_elem = main_elem.querySelector( '#keywords' );  // container for keywords
          var entries = [];                                            // inner container for each keyword

          // has given keywords? => create inner container for each keyword
          if ( my.keywords )
            ( Array.isArray( my.keywords ) ? my.keywords : keywords ).map( addKeyword );
          else
            return keywords_elem.parentNode.removeChild( keywords_elem );  // no given keywords? => remove container for keywords and abort

          // generated keyword list? => sort keywords lexicographical (keyword order gives no hint about correct solution)
          if ( my.keywords === true ) entries.sort( function ( a, b ) { return a.innerHTML.localeCompare( b.innerHTML ) } );

          // add each inner keyword container to container for keywords
          entries.map( function ( entry ) { keywords_elem.appendChild( entry ); } );

          /** adds a inner container for a keyword */
          function addKeyword( keyword ) {
            entries.push( self.ccm.helper.html( my.html_templates.keyword, Array.isArray( my.keywords ) ? keyword : keyword.word ) );
          }

        }

        /** renders the text with containing gaps */
        function renderText() {

          // render text with containing gaps
          text_elem.innerHTML = my.text;

          // render input field in each gap
          self.ccm.helper.makeIterable( main_elem.querySelectorAll( '.gap' ) ).map( function ( gap_elem, i ) {

            // blank input fields and shown keywords? => input fields should give no hint for the length of the searched word
            if ( my.blank && my.keywords ) return gap_elem.appendChild( self.ccm.helper.html( { tag: 'input', type: 'text', oninput: onInput, onchange: onChange } ) );

            // shorter access to keyword
            var keyword = keywords[ i ].word;

            // prepare ccm HTML data for input field
            var input = {
              tag: 'input',
              type: 'text',
              oninput: onInput,
              onchange: onChange,
              maxlength: keyword.length,
              size: keyword.length * 1.5  // works tolerably for words with a length up to 30
            };

            // no blank input fields? => set placeholder attribute
            if ( !my.blank ) {
              input.placeholder = '';
              for ( var j = 0; j < keyword.length; j++ )
                input.placeholder += Math.pow( 2, j ) & keywords[ i ].givens ? keyword.charAt( j ) : '_';
            }

            // render input field in the current gap
            gap_elem.appendChild( self.ccm.helper.html( input ) );

            /** onchange callback for input fields */
            function onChange() {

              var data = { gap: 1 + i, input: this.value };  // input field informations

              // has logger instance? => log change event
              if ( self.logger ) self.logger.log( 'change', data );

              // has individual change callback? => perform it
              if ( my.onchange ) my.onchange( self, data );

            }

            /** oninput callback for input fields */
            function onInput() {

              var data = { gap: 1 + i, input: this.value };  // input field informations

              // has logger instance? => log input event
              if ( self.logger ) self.logger.log( 'input', data );

              // has individual input callback? => perform it
              if ( my.oninput ) my.oninput( self, data );

            }

          } );

        }

        /** renders the finish button */
        function renderButton() {

          // set content of container for finish button
          self.ccm.helper.setContent( button_elem, self.ccm.helper.html( my.html_templates.button, {
            caption: my.button_caption,
            click:   onFinish
          } ) );

          // finish button is a input tag? => allow use of browser specific default caption
          var submit_elem = button_elem.querySelector( 'input[type=submit]' );
          if ( submit_elem && !my.button_caption ) submit_elem.removeAttribute( 'value' );

        }

        /** renders the timer */
        function renderTimer() {

          timer();  // start timer

          /** updates countdown timer */
          function timer() {

            // already finished? => remove timer
            if ( !main_elem.querySelector( '#timer' ) ) return;

            // (re)render timer value
            self.ccm.helper.setContent( timer_elem, self.ccm.helper.html( my.html_templates.timer, timer_value ) );

            // countdown
            if ( timer_value-- )
              self.ccm.helper.wait( 1000, timer );
            else if ( button_elem )
              onFinish();           // perform finish callback at timeout

          }

        }

        /** onclick callback for finish button */
        function onFinish( event ) {

          // prevent page reload
          if ( event ) event.preventDefault();

          time = new Date().getTime() - time;            // calculate result time
          button_elem.innerHTML = '';                    // remove button
          self.ccm.helper.removeElement( timer_elem  );  // remove timer container

          // has user instance? => login user
          if ( self.user ) self.user.login( proceed ); else proceed();

          function proceed() {

            // give visual feedback for correctness
            self.ccm.helper.makeIterable( main_elem.querySelectorAll( '.gap input' ) ).map( function ( gap, i ) {
              var correct = my.ignore_case ? gap.value.toLowerCase() === keywords[ i ].word.toLowerCase() : gap.value === keywords[ i ].word;
              gap.removeAttribute( 'placeholder' );
              gap.parentNode.className += correct ? ' correct' : ' wrong';

              // correct input? => give points
              if ( my.points_per_gap ) {
                results.max_points += my.points_per_gap;
                if ( correct ) results.points += my.points_per_gap;
              }

              // set detail informations for current gap result
              results.details.push( { input: gap.value, solution: keywords[ i ].word, correct: correct } );

            } );

            // finalize result data
            if ( !my.points_per_gap ) { delete results.points; delete results.max_points; }
            if ( self.user ) results.user = self.user.data().key;
            if (   my.time ) results.time_left = timer_value + 1;
            results.time = time;

            // has logger instance? => log finish event
            if ( self.logger ) self.logger.log( 'finish', results );

            // provide result data
            self.ccm.helper.onFinish( self, results );

          }

        }

      };

    }

  };

  var namespace = window.ccm && ccm.components[ component_name ]; if ( namespace ) { if ( namespace.ccm_version ) ccm_version = namespace.ccm_version; if ( namespace.ccm_url ) ccm_url = namespace.ccm_url; }
  if ( !window.ccm || !ccm[ ccm_version ] ) { var tag = document.createElement( 'script' ); document.head.appendChild( tag ); tag.onload = register; tag.src = ccm_url; } else register();
  function register() { ccm[ ccm_version ].component( component_obj ); }
}() );<commit_msg>minor change<commit_after>/**
 * @overview ccm component for fill-in-the-blank texts
 * @author André Kless <andre.kless@web.de> 2017
 * @license The MIT License (MIT)
 */

( function () {

  var ccm_version = '8.0.0';
  var ccm_url     = '../../ccm-developer/ccm/ccm.js';

  var component_name = 'cloze';
  var component_obj  = {

    name: component_name,

    config: {

      text: 'Hello, [[(W)o(rl)d]]!',
      html_templates: {
        main: {
          id: 'main',
          inner: {
            tag: 'form',
            id: 'form',
            inner: [
              { id: 'keywords' },
              { id: 'text' },
              { id: 'button' },
              { id: 'timer' }
            ],
            onsubmit: '%%'
          }
        },
        keyword: {
          class: 'keyword',
          inner: '%%'
        },
        button: {
          tag: 'input',
          type: 'submit',
          value: '%caption%'
        },
        timer: {
          tag: 'span',
          inner: '%%'
        }
      },
      css_layout: [ 'ccm.load', '../cloze/layouts/default.css' ]

  //  blank: true,
  //  ignore_case: true,
  //  keywords: [ 'keyword1', 'keyword2', ... ],
  //  points_per_gap: 1,
  //  time: 60,
  //  button_caption: 'finish',
  //  user: [ 'ccm.instance', '../user/ccm.user.js' ],
  //  logger: [ 'ccm.instance', '../log/ccm.log.js', [ 'ccm.get', '../log/configs.json', 'greedy' ] ],
  //  onchange: function ( instance, data ) { console.log( data ); },
  //  oninput: function ( instance, data ) { console.log( data ); },
  //  onfinish: function ( instance, results ) { console.log( results ); }

    },

    Instance: function () {

      var self = this;
      var my;             // contains privatized instance members
      var keywords = [];  // information data for each keyword

      this.init = function ( callback ) {

        // fill-in-the-blank text is given via inner HTML? => use it with higher priority
        if ( self.node && self.node.innerHTML.trim() ) self.text = self.node.innerHTML;

        callback();
      };

      this.ready = function ( callback ) {

        // privatize all possible instance members
        my = self.ccm.helper.privatize( self );

        var regex_keyword = /\[\[.+?\]\]/g;   // regular expression for finding all gaps/keywords in the text
        var regex_given = /\(.+?\)/g;         // regular expression for finding all given characters of a keyword

        // iterate all keywords in the text to determine the information data for each keyword
        ( my.text.match( regex_keyword ) || [] ).map( function ( keyword ) {

          // remove distinguishing characteristic '[[' and ']]'
          keyword = keyword.substr( 2, keyword.length - 4 );

          // replace all given characters of a keywords with '*'
          var keyw__d = keyword.replace( '*', '#' ).replace( regex_given, function ( given ) {
            var length = given.length - 2;
            given = '';
            for ( var i = 0; i < length; i++ ) given += '*';
            return given;
          } );

          // determine given characters and hold this information in a single number (disadvantage: possible positions
          var givens = 0;                                                      // for given letters in a word are 0-31
          for ( var i = 0; i < keyw__d.length; i++ )                           // because of data type limitations)
            if ( keyw__d.charAt( i ) === '*' ) givens += Math.pow( 2, i );

          // add keyword information data for current keyword
          keywords.push( {
            word: keyword.replace( regex_given, function ( given ) { return given.substr( 1, given.length - 2 ); } ),
            givens: givens
          } );

        } );

        // replace gaps/keywords with empty span elements
        my.text = my.text.replace( regex_keyword, '' );

        callback();
      };

      this.start = function ( callback ) {

        // initial result data
        var results = { points: 0, max_points: 0, details: [] };

        // prepare main HTML structure
        var main_elem = self.ccm.helper.html( my.html_templates.main, onFinish );

        var   text_elem  = main_elem.querySelector( '#text'   );  // container for text with containing gaps
        var button_elem  = main_elem.querySelector( '#button' );  // container for finish button
        var  timer_elem  = main_elem.querySelector( '#timer'  );  // container for timer
        var  timer_value = my.time;                               // timer value

        // add content for inner containers
        renderKeywords();
        renderText();
        renderButton();
        if ( my.time ) renderTimer(); else self.ccm.helper.removeElement( timer_elem );

        // remember start time
        var time = new Date().getTime();

        // set content of own website area
        self.ccm.helper.setContent( self.element, self.ccm.helper.protect( main_elem ) );

        // has logger instance? => log start event
        if ( self.logger ) self.logger.log( 'start', my );

        if ( callback ) callback();

        /**
         * @summary renders given keywords for text gaps
         * @description
         * Keywords could be given (individual) via instance configuration (my.keywords is string array)
         * or (automatic generated) via private variable 'keywords' (my.keywords is boolean true).
         */
        function renderKeywords() {

          var keywords_elem = main_elem.querySelector( '#keywords' );  // container for keywords
          var entries = [];                                            // inner container for each keyword

          // has given keywords? => create inner container for each keyword
          if ( my.keywords )
            ( Array.isArray( my.keywords ) ? my.keywords : keywords ).map( addKeyword );
          else
            return keywords_elem.parentNode.removeChild( keywords_elem );  // no given keywords? => remove container for keywords and abort

          // generated keyword list? => sort keywords lexicographical (keyword order gives no hint about correct solution)
          if ( my.keywords === true ) entries.sort( function ( a, b ) { return a.innerHTML.localeCompare( b.innerHTML ) } );

          // add each inner keyword container to container for keywords
          entries.map( function ( entry ) { keywords_elem.appendChild( entry ); } );

          /** adds a inner container for a keyword */
          function addKeyword( keyword ) {
            entries.push( self.ccm.helper.html( my.html_templates.keyword, Array.isArray( my.keywords ) ? keyword : keyword.word ) );
          }

        }

        /** renders the text with containing gaps */
        function renderText() {

          // render text with containing gaps
          text_elem.innerHTML = my.text;

          // render input field in each gap
          self.ccm.helper.makeIterable( main_elem.querySelectorAll( '.gap' ) ).map( function ( gap_elem, i ) {

            // blank input fields and shown keywords? => input fields should give no hint for the length of the searched word
            if ( my.blank && my.keywords ) return gap_elem.appendChild( self.ccm.helper.html( { tag: 'input', type: 'text', oninput: onInput, onchange: onChange } ) );

            // shorter access to keyword
            var keyword = keywords[ i ].word;

            // prepare ccm HTML data for input field
            var input = {
              tag: 'input',
              type: 'text',
              oninput: onInput,
              onchange: onChange,
              maxlength: keyword.length,
              size: keyword.length * 1.5  // works tolerably for words with a length up to 30
            };

            // no blank input fields? => set placeholder attribute
            if ( !my.blank ) {
              input.placeholder = '';
              for ( var j = 0; j < keyword.length; j++ )
                input.placeholder += Math.pow( 2, j ) & keywords[ i ].givens ? keyword.charAt( j ) : '_';
            }

            // render input field in the current gap
            gap_elem.appendChild( self.ccm.helper.html( input ) );

            /** onchange callback for input fields */
            function onChange() {

              var data = { gap: 1 + i, input: this.value };  // input field informations

              // has logger instance? => log change event
              if ( self.logger ) self.logger.log( 'change', data );

              // has individual change callback? => perform it
              if ( my.onchange ) my.onchange( self, data );

            }

            /** oninput callback for input fields */
            function onInput() {

              var data = { gap: 1 + i, input: this.value };  // input field informations

              // has logger instance? => log input event
              if ( self.logger ) self.logger.log( 'input', data );

              // has individual input callback? => perform it
              if ( my.oninput ) my.oninput( self, data );

            }

          } );

        }

        /** renders the finish button */
        function renderButton() {

          // set content of container for finish button
          self.ccm.helper.setContent( button_elem, self.ccm.helper.html( my.html_templates.button, {
            caption: my.button_caption,
            click:   onFinish
          } ) );

          // finish button is a input tag? => allow use of browser specific default caption
          var submit_elem = button_elem.querySelector( 'input[type=submit]' );
          if ( submit_elem && !my.button_caption ) submit_elem.removeAttribute( 'value' );

        }

        /** renders the timer */
        function renderTimer() {

          timer();  // start timer

          /** updates countdown timer */
          function timer() {

            // already finished? => remove timer
            if ( !main_elem.querySelector( '#timer' ) ) return;

            // (re)render timer value
            self.ccm.helper.setContent( timer_elem, self.ccm.helper.html( my.html_templates.timer, timer_value ) );

            // countdown
            if ( timer_value-- )
              self.ccm.helper.wait( 1000, timer );
            else if ( button_elem )
              onFinish();           // perform finish callback at timeout

          }

        }

        /** onclick callback for finish button */
        function onFinish( event ) {

          // prevent page reload
          if ( event ) event.preventDefault();

          time = new Date().getTime() - time;            // calculate result time
          button_elem.innerHTML = '';                    // remove button
          self.ccm.helper.removeElement( timer_elem  );  // remove timer container

          // has user instance? => login user
          if ( self.user ) self.user.login( proceed ); else proceed();

          function proceed() {

            // give visual feedback for correctness
            self.ccm.helper.makeIterable( main_elem.querySelectorAll( '.gap input' ) ).map( function ( gap, i ) {
              var correct = my.ignore_case ? gap.value.toLowerCase() === keywords[ i ].word.toLowerCase() : gap.value === keywords[ i ].word;
              gap.removeAttribute( 'placeholder' );
              gap.parentNode.className += correct ? ' correct' : ' wrong';

              // correct input? => give points
              if ( my.points_per_gap ) {
                results.max_points += my.points_per_gap;
                if ( correct ) results.points += my.points_per_gap;
              }

              // set detail informations for current gap result
              results.details.push( { input: gap.value, solution: keywords[ i ].word, correct: correct } );

            } );

            // finalize result data
            if ( !my.points_per_gap ) { delete results.points; delete results.max_points; }
            if ( self.user ) results.user = self.user.data().key;
            if (   my.time ) results.time_left = timer_value + 1;
            results.time = time;

            // has logger instance? => log finish event
            if ( self.logger ) self.logger.log( 'finish', results );

            // provide result data
            self.ccm.helper.onFinish( self, results );

          }

        }

      };

    }

  };

  var namespace = window.ccm && ccm.components[ component_name ]; if ( namespace ) { if ( namespace.ccm_version ) ccm_version = namespace.ccm_version; if ( namespace.ccm_url ) ccm_url = namespace.ccm_url; }
  if ( !window.ccm || !ccm[ ccm_version ] ) { var tag = document.createElement( 'script' ); document.head.appendChild( tag ); tag.onload = register; tag.src = ccm_url; } else register();
  function register() { ccm[ ccm_version ].component( component_obj ); }
}() );<|endoftext|>


<commit_before>(function() {
    $(document).ready(function() {
        /*
         * Loads List of TV-Shows direct from monitored RSS
         *
         */
        var loadRssTV = function(type) {
            var div, rssTV = document.getElementById('rss_TV');
            $.ajax({
                url: '/tv',
                type: 'get',
                dataType: 'json',
                cache: false
            }).done(function(data) {
                for(var i in data) {
                    rssTV.appendChild(siteRow(data[i]));
                }
            }).fail(function(data) {
                msg.set('Error loading TV-Shows');
            });
        };
        /*
         * Loads list of Movies as Thumbnails from db
         *
         */
        var loadRssMovies = function() {
            $.ajax({
                url: '/movies',
                type: 'get',
                dataType: 'json',
                cache: false,
            }).done(function(json) {
                var div, i;
                json.sort(function(a, b) {
                    a = new Date(a.lastUpdate);
                    b = new Date(b.lastUpdate);
                    return a > b ? -1 : a < b ? 1 : 0;
                });
                // Start creating Movie-Thumbs
                var li;
                for(i = 0; i < json.length; i++) {
                    div = thumbPosterWithInfoClickable(json[i]);
                    li = document.createElement('li');
                    li.className = 'col-lg-1 col-md-2 col-sm-3 col-xs-4';
                    li.appendChild(div);
                    //div.style.float = 'left';
                    $('#rss_Movies').append(li);
                }
            }).fail(function(data) {
                msg.set('Error while loading movies');
            });
        };
        loadRssTV();
        loadRssMovies();
        loadFiles();
        /*
         * Creates a siteRow which can be parsed
         *
         * @param site  {object} {title, pubdate, link, description}
         *
         *
         */
        var siteRow = function(sites) {
            var div = document.createElement('div');
            div.className = 'hyperlinkParse';
            if(sites.title !== undefined) {
                var domain = sites.link.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
                var date = new Date(sites.pubdate);
                div.innerHTML = sites.title + ' (' + date.easy() + ' @' + domain[1] + ')';
                sites = [sites];
            } else {
                div.textContent = '>- rip All Sites -<';
            }
            div.onclick = (function(sites) {
                return function() {
                    msg.set('parsing site...');
                    $.ajax({
                        url: '/site/links',
                        type: 'POST',
                        data: {
                            sites: sites
                        },
                        cache: false,
                        dataType: 'json'
                    }).done(function(onlineLinks){processLinks(onlineLinks)}).fail(function() {
                        msg.set('Error when checking links!');
                    });
                };
            })(sites);
            return div;
        };
        /*
         * Process returned online links
         */
        var processLinks = function(data) {
            /* structure of data; example
                [
                  {
                    "status": "0",
                    "filename": "Sm.2013.720p-iFT",
                    "extension": "mkv",
                    "size": "4920000000",
                    "link": "http://ul.to/08otd5be"
                  }
                  { etc. }
                ]
            */
            msg.set('found ' + data.length + ' links.')
            makeTableChecked(data);
            // Add links to textarea for exporting
            $('#paste').html(data.map(function(elem) {
                return elem.link;
            }).join(' '));
            $('.nav-tabs a[href="#tabLinks"]').tab('show');
        };
        /*
         * One Row of FileExplorer
         */
        var fileRow = function(file) {
            var tr = document.createElement('tr');
            var td = [];
            for(s = 0; s < 4; s++) {
                td.push(document.createElement('td'));
            }
            var a = null,
                icon = null,
                del = null,
                s = 0,
                i = 0;
            // Filename Link
            a = document.createElement('a');
            a.href = 'files/' + file.link;
            a.textContent = file.filename;
            td[0].appendChild(a);
            td[1].textContent = bytesToSize(file.size);
            // Filetype Icon
            icon = document.createElement('div');
            icon.className = 'icon icon' + file.extension;
            icon.title = file.extension;
            td[2].appendChild(icon);
            // DELETE Link
            del = document.createElement('div');
            del.className = 'a';
            del.onclick = function() {
                $.ajax({
                    url: 'files/' + file.link + '/delete',
                    type: 'DELETE',
                    dataType: 'json'
                }).done(function(err) {
                    err === null && msg.set('File Deleted', 'fadeout');
                    loadFiles(); // reload files-table
                }).fail(function() {
                    msg.set('Problem with connection; try again.', 'fadeout');
                });
            };
            del.textContent = 'delete';
            td[3].appendChild(del);
            for(s = 0; s < 4; s++) {
                tr.appendChild(td[s]);
            }
            return tr;
        };

        /**
         * Creates a HTML Movie-Thumb from the Movie-Poster
         *
         * @param {string} imageUrl The Url of the Movie-Poster-Image
         * @param {string} title Title of the Movie as title-tag
         *
         * @returns {Object} the DOM-Object of the div
         */
        var thumbPoster = function(imageUrl, title, year) {
            var img = document.createElement('img');
            img.src = imageUrl;
            img.className = 'thumbPosterImg thumb thumbnail';
            img.style.height = '250px';
            var divTitle = document.createElement('div');
            var div = document.createElement('div');
            div.className = 'thumbPoster';
            divTitle.title = title + ' (' + year + ')';
            divTitle.className = 'thumbPosterTitle';
            divTitle.textContent = title;
            if(imageUrl === 'http://image.tmdb.org/t/p/w500null' || (/poster_default/).test(imageUrl)) {
                div.width = '10vw';
                div.style.minHeight = '50px';
                div.appendChild(divTitle);

            } else {
                div.appendChild(img);
            }
            return div;
        };
        /**
         * Adds info to the movie-Thumb (Resolution, etc.)
         */
        var thumbPosterWithInfo = function(imageUrl, title, year, resolutions) {
            var thumb = thumbPoster(imageUrl, title, year);
            var divRes = document.createElement('div');
            divRes.className = 'resolutionBar';
            divRes.textContent = resolutions.join(', ');
            //thumb.appendChild(divRes);
            return thumb;
        };
        var thumbPosterWithInfoClickable = function(mData) {
            imgUrl = mData.info.posters !== undefined ? mData.info.posters.thumbnail : '';
            var div = thumbPosterWithInfo(imgUrl, mData.title, mData.info.year, mData.resolutions);
            div.style.cursor = 'pointer';
            div.onclick = (function(_id, title, info, image, sites, div) {
                return function() {
                    $('.nav-tabs a[href="#tabLinks"]').tab('show');
                    $('#linksDetails').empty();
                    $('#linksDetails').append(divMovieInfo(_id, title, image, info.runtime ? info.runtime : '?', info.year, 'imdb-Rating', info.synopsis === '' ? 'no synopsis' : info.synopsis, 'actors', div));
                    // Site-Links for ripping links
                    var linkList = document.getElementById('linksDetails');
                    // Link to Rip all links at the same time
                    linkList.appendChild(siteRow(sites));
                    // Single Links that can be parsed
                    for(var key in sites) {
                        linkList.appendChild(siteRow(sites[key]));
                    }
                };
            })(mData._id, mData.title, mData.info, imgUrl, mData.sites, div);
            return div;
        };
        /**
         * Creates the Movie-Info-Card
         */
        var divMovieInfo = function(_id, title, posterUrl, runtime, year, imdb, synopsis, actors, thumbDiv) {
            var div = document.createElement('div');
            div.className = 'movieDigest';
            var divOuter = document.createElement('div');
            divOuter.className = 'movieInfo';
            var divTitle = document.createElement('div');
            divTitle.className = 'movieInfoTitle';
            divTitle.textContent = title;
            var divDetails = document.createElement('div');
            divDetails.className = 'movieInfoLine';
            divDetails.textContent = 'Length: ' + runtime + 'min, Year: ' + year + ', ';
            var spanRemove = createElementSpanRemove(_id, thumbDiv);
            divDetails.appendChild(spanRemove);
            divDetails.appendChild(createElementSpanSpace());
            var spanUpdate = createElementSpanUpdate(_id);
            divDetails.appendChild(spanUpdate);
            var divSynopsis = document.createElement('div');
            divSynopsis.className = 'movieInfoLine';
            divSynopsis.textContent = synopsis;
            divSynopsis.style.fontStyle = 'italic';
            var poster = thumbPoster(posterUrl, title, year);
            poster.style.float = 'left';
            divOuter.appendChild(divTitle);
            divOuter.appendChild(divDetails);
            divOuter.appendChild(divSynopsis);
            div.appendChild(poster);
            div.appendChild(divOuter);
            return div;
        };
        /**
         * creates a space-span of len white spaces
         */
        var createElementSpanSpace = function(len) {
            if(len === undefined) len = 1;
            var span = document.createElement('span');
            var space = '';
            for(var i = 0; i < len; i++) {
                space += ' ';
            }
            span.textContent = space;
            return span;
        };
        /**
         * Creates a link which removes a movie from future display
         */
        var createElementSpanRemove = function(id, thumbDiv) {
            var span = document.createElement('span');
            span.textContent = 'remove';
            span.title = 'don\'t display this movie anymore.';
            span.className = 'hyperlink';
            span.onclick = function() {
                $.getJSON('/movie/' + id + '/hide', function(data) {
                    msg.set('Movie will not be shown anymore!', 'fadeout');
                    $('.nav-tabs a[href="#tabHome"]').tab('show');
                    thumbDiv.parentNode.removeChild(thumbDiv);
                });
            }
            return span;
        };

        /*
         * Creates a link which updates a movie-info
         */
        var createElementSpanUpdate = function(id) {
            var span = document.createElement('span');
            span.textContent = 'update';
            span.title = 'update info to this movie';
            span.className = 'hyperlink';
            span.onclick = function() {
                $.getJSON('/movie/' + id + '/update', function(data) {
                    msg.set('Movie-Info Updated', 'fadeout');
                });
            }
            return span;
        };

        /*
         * Create a Link that can be parsed (for one or multiple Links)
         */
        var parseLink = function(text, sites, clickEvent) {
            var div = document.createElement('div');
            div.className = 'hyperlinkParse';
            div.textContent = text;
            div.onclick = function() {
                clickEvent(sites);
            };
            return div;
        };

        /*
         * Table with ul.to links that have been checked for availability
         *
         * @param {array} files an Array containing all checked ul.to links
         */
        var makeTableChecked = function(files) {
            // one tab for every extension; integer is filecount per extension
            var extensions = {
                mp4: 0,
                mkv: 0,
                avi: 0,
                rar: 0,
                default: 0
            };
            var rowcols = ['link', 'size', 'extension', 'jd', 'cloud'];
            var target = '#tabs-links-';
            // empty all tabs
            for(var i in extensions) $(target + i + ' tbody').empty();
            var cols = function() {
                var tds = [];
                for(var i in rowcols) tds.push(document.createElement('td'));
                return tds;
            };
            // sort files by extension
            files.sort(function(a, b) {
                return a.extension  b.extension ? -1 : 0;
            });
            var makeRow = function(filename, href, extension, size) {
                // create new DOM-table-row
                var tr = document.createElement('tr');
                // create cells
                var tds = [];
                for(var i in rowcols) tds.push(document.createElement('td'));
                // Link/Name Col
                var link = document.createElement('a');
                link.href = href;
                link.textContent = filename;
                tds[0].appendChild(link);
                // Size Col
                tds[1].textContent = bytesToSize(size);
                // Extension Col
                var extension = document.createElement('div');
                extension.className = 'icon icon' + extension;
                extension.title = extension;
                tds[2].appendChild(extension);
                // J-Downloader Col
                tds[3].appendChild(jDLink(link));
                // Download to Server Col
                var cloud = document.createElement('div');
                cloud.className = 'icon iconcloud';
                cloud.title = 'download to server';
                cloud.onclick = (function(link) {
                    return function() {
                        console.log(link);
                        plowdown(link);
                    };
                })(link);
                tds[4].appendChild(cloud);
                for(var key in tds) tr.appendChild(tds[key]);
                return tr;
            };
            // Loop through all files
            for(i in files) {
                var t = (extensions[files[i].extension] !== undefined) ? files[i].extension : 'default';
                extensions[t]++;
                var tr = makeRow(files[i].filename, files[i].link, files[i].extension, files[i].size);
                $(target + t + ' tbody').append(tr);
            }
            // update files per extension
            if(extensions.mp4 === 0) {
                $('.nav-tabs a[href="#tabLinks"]').tab('show');
            } else $('#rssLinks').tabs({
                active: 0
            });
            // Update Tab-title counter
            for(var i in extensions) {
                $('#rssLinks ul:first li:eq(' + (Object.keys(extensions)).indexOf(i) + ') a').text(i + '(' + extensions[i] + ')');
            }
        };
    });
})();<commit_msg>implement bootstrap<commit_after>(function() {
    $(document).ready(function() {
        /*
         * Loads List of TV-Shows direct from monitored RSS
         *
         */
        var loadRssTV = function(type) {
            var div, rssTV = document.getElementById('rss_TV');
            $.ajax({
                url: '/tv',
                type: 'get',
                dataType: 'json',
                cache: false
            }).done(function(data) {
                for(var i in data) {
                    rssTV.appendChild(siteRow(data[i]));
                }
            }).fail(function(data) {
                msg.set('Error loading TV-Shows');
            });
        };
        /*
         * Loads list of Movies as Thumbnails from db
         *
         */
        var loadRssMovies = function() {
            $.ajax({
                url: '/movies',
                type: 'get',
                dataType: 'json',
                cache: false,
            }).done(function(json) {
                var div, i;
                json.sort(function(a, b) {
                    a = new Date(a.lastUpdate);
                    b = new Date(b.lastUpdate);
                    return a > b ? -1 : a < b ? 1 : 0;
                });
                // Start creating Movie-Thumbs
                var li;
                for(i = 0; i < json.length; i++) {
                    div = thumbPosterWithInfoClickable(json[i]);
                    li = document.createElement('li');
                    li.className = 'col-lg-1 col-md-2 col-sm-3 col-xs-4';
                    li.appendChild(div);
                    //div.style.float = 'left';
                    $('#rss_Movies').append(li);
                }
            }).fail(function(data) {
                msg.set('Error while loading movies');
            });
        };
        loadRssTV();
        loadRssMovies();
        loadFiles();
        /*
         * Creates a siteRow which can be parsed
         *
         * @param site  {object} {title, pubdate, link, description}
         *
         *
         */
        var siteRow = function(sites) {
            var div = document.createElement('div');
            div.className = 'hyperlinkParse';
            if(sites.title !== undefined) {
                var domain = sites.link.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
                var date = new Date(sites.pubdate);
                div.innerHTML = sites.title + ' (' + date.easy() + ' @' + domain[1] + ')';
                sites = [sites];
            } else {
                div.textContent = '>- rip All Sites -<';
            }
            div.onclick = (function(sites) {
                return function() {
                    msg.set('parsing site...');
                    $.ajax({
                        url: '/site/links',
                        type: 'POST',
                        data: {
                            sites: sites
                        },
                        cache: false,
                        dataType: 'json'
                    }).done(function(onlineLinks){processLinks(onlineLinks)}).fail(function() {
                        msg.set('Error when checking links!');
                    });
                };
            })(sites);
            return div;
        };
        /*
         * Process returned online links
         */
        var processLinks = function(data) {
            /* structure of data; example
                [
                  {
                    "status": "0",
                    "filename": "Sm.2013.720p-iFT",
                    "extension": "mkv",
                    "size": "4920000000",
                    "link": "http://ul.to/08otd5be"
                  }
                  { etc. }
                ]
            */
            msg.set('found ' + data.length + ' links.')
            makeTableChecked(data);
            // Add links to textarea for exporting
            $('#paste').html(data.map(function(elem) {
                return elem.link;
            }).join(' '));
            $('.nav-tabs a[href="#tabLinks"]').tab('show');
        };
        /*
         * One Row of FileExplorer
         */
        var fileRow = function(file) {
            var tr = document.createElement('tr');
            var td = [];
            for(s = 0; s < 4; s++) {
                td.push(document.createElement('td'));
            }
            var a = null,
                icon = null,
                del = null,
                s = 0,
                i = 0;
            // Filename Link
            a = document.createElement('a');
            a.href = 'files/' + file.link;
            a.textContent = file.filename;
            td[0].appendChild(a);
            td[1].textContent = bytesToSize(file.size);
            // Filetype Icon
            icon = document.createElement('div');
            icon.className = 'icon icon' + file.extension;
            icon.title = file.extension;
            td[2].appendChild(icon);
            // DELETE Link
            del = document.createElement('div');
            del.className = 'a';
            del.onclick = function() {
                $.ajax({
                    url: 'files/' + file.link + '/delete',
                    type: 'DELETE',
                    dataType: 'json'
                }).done(function(err) {
                    err === null && msg.set('File Deleted', 'fadeout');
                    loadFiles(); // reload files-table
                }).fail(function() {
                    msg.set('Problem with connection; try again.', 'fadeout');
                });
            };
            del.textContent = 'delete';
            td[3].appendChild(del);
            for(s = 0; s < 4; s++) {
                tr.appendChild(td[s]);
            }
            return tr;
        };

        /**
         * Creates a HTML Movie-Thumb from the Movie-Poster
         *
         * @param {string} imageUrl The Url of the Movie-Poster-Image
         * @param {string} title Title of the Movie as title-tag
         *
         * @returns {Object} the DOM-Object of the div
         */
        var thumbPoster = function(imageUrl, title, year) {
            var img = document.createElement('img');
            img.src = imageUrl;
            img.className = 'thumbPosterImg thumb thumbnail';
            img.style.height = '180px';
            var divTitle = document.createElement('div');
            var div = document.createElement('div');
            div.className = 'thumbPoster';
            divTitle.title = title + ' (' + year + ')';
            divTitle.className = 'thumbPosterTitle';
            divTitle.textContent = title;
            if(imageUrl === 'http://image.tmdb.org/t/p/w500null' || (/poster_default/).test(imageUrl)) {
                div.width = '10vw';
                div.style.minHeight = '50px';
                div.appendChild(divTitle);

            } else {
                div.appendChild(img);
            }
            return div;
        };
        /**
         * Adds info to the movie-Thumb (Resolution, etc.)
         */
        var thumbPosterWithInfo = function(imageUrl, title, year, resolutions) {
            var thumb = thumbPoster(imageUrl, title, year);
            var divRes = document.createElement('div');
            divRes.className = 'resolutionBar';
            divRes.textContent = resolutions.join(', ');
            //thumb.appendChild(divRes);
            return thumb;
        };
        var thumbPosterWithInfoClickable = function(mData) {
            imgUrl = mData.info.posters !== undefined ? mData.info.posters.thumbnail : '';
            var div = thumbPosterWithInfo(imgUrl, mData.title, mData.info.year, mData.resolutions);
            div.style.cursor = 'pointer';
            div.onclick = (function(_id, title, info, image, sites, div) {
                return function() {
                    $('.nav-tabs a[href="#tabLinks"]').tab('show');
                    $('#linksDetails').empty();
                    $('#linksDetails').append(divMovieInfo(_id, title, image, info.runtime ? info.runtime : '?', info.year, 'imdb-Rating', info.synopsis === '' ? 'no synopsis' : info.synopsis, 'actors', div));
                    // Site-Links for ripping links
                    var linkList = document.getElementById('linksDetails');
                    // Link to Rip all links at the same time
                    linkList.appendChild(siteRow(sites));
                    // Single Links that can be parsed
                    for(var key in sites) {
                        linkList.appendChild(siteRow(sites[key]));
                    }
                };
            })(mData._id, mData.title, mData.info, imgUrl, mData.sites, div);
            return div;
        };
        /**
         * Creates the Movie-Info-Card
         */
        var divMovieInfo = function(_id, title, posterUrl, runtime, year, imdb, synopsis, actors, thumbDiv) {
            var div = document.createElement('div');
            div.className = 'movieDigest';
            var divOuter = document.createElement('div');
            divOuter.className = 'movieInfo';
            var divTitle = document.createElement('div');
            divTitle.className = 'movieInfoTitle';
            divTitle.textContent = title;
            var divDetails = document.createElement('div');
            divDetails.className = 'movieInfoLine';
            divDetails.textContent = 'Length: ' + runtime + 'min, Year: ' + year + ', ';
            var spanRemove = createElementSpanRemove(_id, thumbDiv);
            divDetails.appendChild(spanRemove);
            divDetails.appendChild(createElementSpanSpace());
            var spanUpdate = createElementSpanUpdate(_id);
            divDetails.appendChild(spanUpdate);
            var divSynopsis = document.createElement('div');
            divSynopsis.className = 'movieInfoLine';
            divSynopsis.textContent = synopsis;
            divSynopsis.style.fontStyle = 'italic';
            var poster = thumbPoster(posterUrl, title, year);
            poster.style.float = 'left';
            divOuter.appendChild(divTitle);
            divOuter.appendChild(divDetails);
            divOuter.appendChild(divSynopsis);
            div.appendChild(poster);
            div.appendChild(divOuter);
            return div;
        };
        /**
         * creates a space-span of len white spaces
         */
        var createElementSpanSpace = function(len) {
            if(len === undefined) len = 1;
            var span = document.createElement('span');
            var space = '';
            for(var i = 0; i < len; i++) {
                space += ' ';
            }
            span.textContent = space;
            return span;
        };
        /**
         * Creates a link which removes a movie from future display
         */
        var createElementSpanRemove = function(id, thumbDiv) {
            var span = document.createElement('span');
            span.textContent = 'remove';
            span.title = 'don\'t display this movie anymore.';
            span.className = 'hyperlink';
            span.onclick = function() {
                $.getJSON('/movie/' + id + '/hide', function(data) {
                    msg.set('Movie will not be shown anymore!', 'fadeout');
                    $('.nav-tabs a[href="#tabHome"]').tab('show');
                    thumbDiv.parentNode.removeChild(thumbDiv);
                });
            }
            return span;
        };

        /*
         * Creates a link which updates a movie-info
         */
        var createElementSpanUpdate = function(id) {
            var span = document.createElement('span');
            span.textContent = 'update';
            span.title = 'update info to this movie';
            span.className = 'hyperlink';
            span.onclick = function() {
                $.getJSON('/movie/' + id + '/update', function(data) {
                    msg.set('Movie-Info Updated', 'fadeout');
                });
            }
            return span;
        };

        /*
         * Create a Link that can be parsed (for one or multiple Links)
         */
        var parseLink = function(text, sites, clickEvent) {
            var div = document.createElement('div');
            div.className = 'hyperlinkParse';
            div.textContent = text;
            div.onclick = function() {
                clickEvent(sites);
            };
            return div;
        };

        /*
         * Table with ul.to links that have been checked for availability
         *
         * @param {array} files an Array containing all checked ul.to links
         */
        var makeTableChecked = function(files) {
            // one tab for every extension; integer is filecount per extension
            var extensions = {
                mp4: 0,
                mkv: 0,
                avi: 0,
                rar: 0,
                default: 0
            };
            var rowcols = ['link', 'size', 'extension', 'jd', 'cloud'];
            var target = '#tabs-links-';
            // empty all tabs
            for(var i in extensions) $(target + i + ' tbody').empty();
            var cols = function() {
                var tds = [];
                for(var i in rowcols) tds.push(document.createElement('td'));
                return tds;
            };
            // sort files by extension
            files.sort(function(a, b) {
                return a.extension  b.extension ? -1 : 0;
            });
            var makeRow = function(filename, href, extension, size) {
                // create new DOM-table-row
                var tr = document.createElement('tr');
                // create cells
                var tds = [];
                for(var i in rowcols) tds.push(document.createElement('td'));
                // Link/Name Col
                var link = document.createElement('a');
                link.href = href;
                link.textContent = filename;
                tds[0].appendChild(link);
                // Size Col
                tds[1].textContent = bytesToSize(size);
                // Extension Col
                var extension = document.createElement('div');
                extension.className = 'icon icon' + extension;
                extension.title = extension;
                tds[2].appendChild(extension);
                // J-Downloader Col
                tds[3].appendChild(jDLink(link));
                // Download to Server Col
                var cloud = document.createElement('div');
                cloud.className = 'icon iconcloud';
                cloud.title = 'download to server';
                cloud.onclick = (function(link) {
                    return function() {
                        console.log(link);
                        plowdown(link);
                    };
                })(link);
                tds[4].appendChild(cloud);
                for(var key in tds) tr.appendChild(tds[key]);
                return tr;
            };
            // Loop through all files
            for(i in files) {
                var t = (extensions[files[i].extension] !== undefined) ? files[i].extension : 'default';
                extensions[t]++;
                var tr = makeRow(files[i].filename, files[i].link, files[i].extension, files[i].size);
                $(target + t + ' tbody').append(tr);
            }
            // update files per extension
            if(extensions.mp4 === 0) {
                $('.nav-tabs a[href="#tabLinks"]').tab('show');
            } else $('#rssLinks').tabs({
                active: 0
            });
            // Update Tab-title counter
            for(var i in extensions) {
                $('#rssLinks ul:first li:eq(' + (Object.keys(extensions)).indexOf(i) + ') a').text(i + '(' + extensions[i] + ')');
            }
        };
    });
})();<|endoftext|>


<commit_before>$(function () {
	getAll(function (data) {
		renderChart(data);
	});
});

var renderChart = function(data) {

	var flotdata = convertDataForFlot(data);

	var detailPlaceholder = $('#detail-placeholder');
	var detailPlot = $.plot(detailPlaceholder, flotdata, {
		xaxis: { mode: 'time' },
		series: {
			lines: { show: true },
			points: { show: true }
		},
		legend: { show: true },
		grid: {
			hoverable: true,
			clickable: true
		},
		selection: { mode: 'x' },
		crosshair: { mode: '' }
	});

	var overviewPlaceholder = $('#overview-placeholder');
	var overviewPlot = $.plot(overviewPlaceholder, flotdata, {
		series: {
			lines: { show: true, lineWidth: 1 },
			shadowSize: 0,
			points: { show: false }
		},
		xaxis: { ticks: [], mode: "time" },
		yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 },
		legend: { show: false },
		grid: { hoverable: true },
		selection: { mode: 'x' },
		crosshair: { mode: 'x' }
	});

	showTooltip(detailPlaceholder);
	zoom(detailPlot, detailPlaceholder, overviewPlot, overviewPlaceholder);
	pane(detailPlot, detailPlaceholder);

	$('#show-all').click(function (event) {
		event.preventDefault();
		detailPlot.setSelection(
			{ xaxis: {
				from: detailPlot.getData()[0].data[0][0],
				to: detailPlot.getData()[0].data[detailPlot.getData()[0].data.length - 1][0] }
			});
		overviewPlot.clearSelection();
	});
};

var zoom = function (plot, placeholder, overview, overviewPlaceholder) {

	var min = plot.getData()[0].data[0][0];
	var lastEntryPos = plot.getData()[0].data.length - 1;
	var max = plot.getData()[0].data[lastEntryPos][0];

	var currentRange;

	// Zoom in (only x axis)
	placeholder.bind('plotselected', function (event, ranges) {
		$.each(plot.getXAxes(), function (_, axis) {
			var opts = axis.options;
			opts.min = ranges.xaxis.from;
			opts.max = ranges.xaxis.to;
		});
		plot.setupGrid();
		plot.draw();
		plot.clearSelection();

		overview.setSelection(ranges, true);
	});

	overviewPlaceholder.bind('plotselected', function (event, ranges) {
		console.log('ranges overview');
		console.log(ranges.xaxis);
		console.log('xaxis min: ' + overview.getXAxes()[0].min);
		console.log('xaxis max: ' + overview.getXAxes()[0].max);
		console.log(event);
		currentRange = ranges.xaxis;

		plot.setSelection(ranges);
	});

	// hover range borders -------------------------------------------------------------------
	var dragRangeInPixel = 10;

	$('

')
		.appendTo(overviewPlaceholder)
		.css({
			cursor: 'col-resize',
			position: 'absolute',
			top: '6px',
			width: dragRangeInPixel + 'px',
			height: '88px',
			border: '1px solid red', // <-- for debugging
			display: 'none'
		});

	// NOTE: To use 'plothover' the plot option 'grid: { hoverable: true }' is required!
	overviewPlaceholder.bind('plothover', function (event, pos, item) {
		if (currentRange) {
			var from = overview.p2c({ x: currentRange.from, y: pos.y });
			var to = overview.p2c({ x: currentRange.to, y: 0 });
			var currentXPosPixel = overview.p2c({ x: pos.x, y: pos.y }).left;

			var isInDragRange = function (currentX, targetX) {
				return currentX >= (targetX.left - (dragRangeInPixel/2)) &&
					currentX <= (targetX.left + (dragRangeInPixel/2));
			};

			if (isInDragRange(currentXPosPixel, from)) {
				$('#dragCursor').css({left: from.left + (dragRangeInPixel/2), display: '' });
			} else if (isInDragRange(currentXPosPixel, to)) {
				$('#dragCursor').css({left: to.left + (dragRangeInPixel/2), display: '' });
			} else {
				$('#dragCursor').hide();
			}
		}
	});
};

var showTooltip = function(placeholder){
	$('

').css({
		position: 'absolute',
		display: 'none',
		border: '1px solid #fdd',
		padding: '2px',
		'background-color': '#fee',
		opacity: 0.80
	}).appendTo('body');

	placeholder.bind('plothover', function (event, pos, item) {
		if (item) {
			var x = item.datapoint[0],
				y = item.datapoint[1].toFixed(1);
			$('#tooltip').html(formatDate(x) + ' : ' + y + '°C')
				.css({top: item.pageY+5, left: item.pageX+5})
				.fadeIn(200);
		} else {
			$('#tooltip').hide();
		}
	});
};

var pane = function (plot, placeholder) {
	function addArrow(dir, right, top, offset) {
		$("")
			.appendTo(placeholder)
			.click(function (e) {
				e.preventDefault();
				plot.pan(offset);
			});
	}

	addArrow('left', 600, 275, {left: -50});
	addArrow('right', -20, 275, {left: 50});
};

// Prepare data -------------------------------------------------------------------------------------------
var formatDate = function(date) {
	// requires moment.js
	return moment.utc(new Date(date)).format('ddd, YYYY MMM DD HH:mm');
};

var convertDataForFlot = function(data) {
	var flotdata = [];
	flotdata.push(mapTimeSeries(data, 'WA', 'outside'));
	flotdata.push(mapTimeSeries(data, 'Z2', '2nd floor'));
	return flotdata;
};

var mapTimeSeries = function (data, sensorName, label) {
	var series = [];
	for(var i = 0; i < data.length; i++) {
		if (data[i].sensorName === sensorName) {

			// Note: Flot library expects time series data to be in milliseconds since 1970 ('.getTime()').
			// Flot library does not care about time zones.
			var dateWithTimezone = new Date(data[i].timestamp);
			var milliSecondsSince1970Utc = dateWithTimezone.getTime();
			var offsetInMinutes = dateWithTimezone.getTimezoneOffset();
			var offsetInMilliSeconds = offsetInMinutes * 60 * 1000;

			// We have to subtract (!) the time zone difference to fake a new utc time matching our local time zone.
			var fakedUtcTimeInMilliSeconds = milliSecondsSince1970Utc - offsetInMilliSeconds;

			series.push([ fakedUtcTimeInMilliSeconds, data[i].degreeCelsius ]);
		}
	}
	return { data: series, label: label };
};
<commit_msg>removed unused variables after adding show all button<commit_after>$(function () {
	getAll(function (data) {
		renderChart(data);
	});
});

var renderChart = function(data) {

	var flotdata = convertDataForFlot(data);

	var detailPlaceholder = $('#detail-placeholder');
	var detailPlot = $.plot(detailPlaceholder, flotdata, {
		xaxis: { mode: 'time' },
		series: {
			lines: { show: true },
			points: { show: true }
		},
		legend: { show: true },
		grid: {
			hoverable: true,
			clickable: true
		},
		selection: { mode: 'x' },
		crosshair: { mode: '' }
	});

	var overviewPlaceholder = $('#overview-placeholder');
	var overviewPlot = $.plot(overviewPlaceholder, flotdata, {
		series: {
			lines: { show: true, lineWidth: 1 },
			shadowSize: 0,
			points: { show: false }
		},
		xaxis: { ticks: [], mode: "time" },
		yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 },
		legend: { show: false },
		grid: { hoverable: true },
		selection: { mode: 'x' },
		crosshair: { mode: 'x' }
	});

	showTooltip(detailPlaceholder);
	zoom(detailPlot, detailPlaceholder, overviewPlot, overviewPlaceholder);
	pane(detailPlot, detailPlaceholder);

	$('#show-all').click(function (event) {
		event.preventDefault();
		detailPlot.setSelection(
			{ xaxis: {
				from: detailPlot.getData()[0].data[0][0],
				to: detailPlot.getData()[0].data[detailPlot.getData()[0].data.length - 1][0] }
			});
		overviewPlot.clearSelection();
	});
};

var zoom = function (plot, placeholder, overview, overviewPlaceholder) {

	var currentRange;

	// Zoom in (only x axis)
	placeholder.bind('plotselected', function (event, ranges) {
		$.each(plot.getXAxes(), function (_, axis) {
			var opts = axis.options;
			opts.min = ranges.xaxis.from;
			opts.max = ranges.xaxis.to;
		});
		plot.setupGrid();
		plot.draw();
		plot.clearSelection();

		overview.setSelection(ranges, true);
	});

	overviewPlaceholder.bind('plotselected', function (event, ranges) {
		console.log('ranges overview');
		console.log(ranges.xaxis);
		console.log('xaxis min: ' + overview.getXAxes()[0].min);
		console.log('xaxis max: ' + overview.getXAxes()[0].max);
		console.log(event);
		currentRange = ranges.xaxis;

		plot.setSelection(ranges);
	});

	// hover range borders -------------------------------------------------------------------
	var dragRangeInPixel = 10;

	$('

')
		.appendTo(overviewPlaceholder)
		.css({
			cursor: 'col-resize',
			position: 'absolute',
			top: '6px',
			width: dragRangeInPixel + 'px',
			height: '88px',
			border: '1px solid red', // <-- for debugging
			display: 'none'
		});

	// NOTE: To use 'plothover' the plot option 'grid: { hoverable: true }' is required!
	overviewPlaceholder.bind('plothover', function (event, pos, item) {
		if (currentRange) {
			var from = overview.p2c({ x: currentRange.from, y: pos.y });
			var to = overview.p2c({ x: currentRange.to, y: 0 });
			var currentXPosPixel = overview.p2c({ x: pos.x, y: pos.y }).left;

			var isInDragRange = function (currentX, targetX) {
				return currentX >= (targetX.left - (dragRangeInPixel/2)) &&
					currentX <= (targetX.left + (dragRangeInPixel/2));
			};

			if (isInDragRange(currentXPosPixel, from)) {
				$('#dragCursor').css({left: from.left + (dragRangeInPixel/2), display: '' });
			} else if (isInDragRange(currentXPosPixel, to)) {
				$('#dragCursor').css({left: to.left + (dragRangeInPixel/2), display: '' });
			} else {
				$('#dragCursor').hide();
			}
		}
	});
};

var showTooltip = function(placeholder){
	$('

').css({
		position: 'absolute',
		display: 'none',
		border: '1px solid #fdd',
		padding: '2px',
		'background-color': '#fee',
		opacity: 0.80
	}).appendTo('body');

	placeholder.bind('plothover', function (event, pos, item) {
		if (item) {
			var x = item.datapoint[0],
				y = item.datapoint[1].toFixed(1);
			$('#tooltip').html(formatDate(x) + ' : ' + y + '°C')
				.css({top: item.pageY+5, left: item.pageX+5})
				.fadeIn(200);
		} else {
			$('#tooltip').hide();
		}
	});
};

var pane = function (plot, placeholder) {
	function addArrow(dir, right, top, offset) {
		$("")
			.appendTo(placeholder)
			.click(function (e) {
				e.preventDefault();
				plot.pan(offset);
			});
	}

	addArrow('left', 600, 275, {left: -50});
	addArrow('right', -20, 275, {left: 50});
};

// Prepare data -------------------------------------------------------------------------------------------
var formatDate = function(date) {
	// requires moment.js
	return moment.utc(new Date(date)).format('ddd, YYYY MMM DD HH:mm');
};

var convertDataForFlot = function(data) {
	var flotdata = [];
	flotdata.push(mapTimeSeries(data, 'WA', 'outside'));
	flotdata.push(mapTimeSeries(data, 'Z2', '2nd floor'));
	return flotdata;
};

var mapTimeSeries = function (data, sensorName, label) {
	var series = [];
	for(var i = 0; i < data.length; i++) {
		if (data[i].sensorName === sensorName) {

			// Note: Flot library expects time series data to be in milliseconds since 1970 ('.getTime()').
			// Flot library does not care about time zones.
			var dateWithTimezone = new Date(data[i].timestamp);
			var milliSecondsSince1970Utc = dateWithTimezone.getTime();
			var offsetInMinutes = dateWithTimezone.getTimezoneOffset();
			var offsetInMilliSeconds = offsetInMinutes * 60 * 1000;

			// We have to subtract (!) the time zone difference to fake a new utc time matching our local time zone.
			var fakedUtcTimeInMilliSeconds = milliSecondsSince1970Utc - offsetInMilliSeconds;

			series.push([ fakedUtcTimeInMilliSeconds, data[i].degreeCelsius ]);
		}
	}
	return { data: series, label: label };
};
<|endoftext|>


<commit_before>var colors = {
    0: "lightgray",
    1: "#edc240",
    2: "#afd8f8",
    3: "#cb4b4b",
    4: "#4da74d",
    5: "#9440ed",
    6: "rgb(189, 155, 51)",
    7: "rgb(140,172,198)"
};

$(function () {
    getAll(function (rawdata) {

        var data = convertDataForFlot(rawdata);

        // Legend -------------------------------------------------------------
        var legendContainer = $('#detail-legend');
        $.each(data, function (key, val) {
            legendContainer.append("
<input type='checkbox' name='" + key + "' checked='checked' id='id" + key + "'></input>" +
                "

" +
                "" + val.label + "");
        });

        legendContainer.find("input").click(updatePlot);

        var currentSelection = {
            min: undefined,
            max: undefined
        };

        // Main plotting function ---------------------------------------------
        function updatePlot() {

            var plotdata = [];

            legendContainer.find('input:checked').each(function () {
                var key = $(this).attr('name');
                if (key && data[key]) {
                    plotdata.push(data[key])
                }
            });

            var rangeselectionCallback = function (o) {
                var xaxis = detailPlot.getAxes().xaxis;
                xaxis.options.min = o.start;
                xaxis.options.max = o.end;
                detailPlot.setupGrid();
                detailPlot.draw();

                currentSelection.min = o.start;
                currentSelection.max = o.end;
            };

            var detailPlaceholder = $('#detail-placeholder');
            var detailPlot = $.plot(detailPlaceholder, plotdata, {
                xaxis: {
                    mode: 'time'
                },
                series: {
                    lines: {
                        show: true
                    },
                    points: {
                        show: false
                    }
                },
                legend: {
                    show: false // Note: The legend is configured manually (see legendContainer)
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    autoHighlight: false
                },
                crosshair: {
                    mode: 'x'
                }
            });

            var overviewPlaceholder = $('#overview-placeholder');
            var overviewData = $.extend(true, [], plotdata);
            for (var i = 0; i < overviewData.length; i++) {
                overviewData[i].color = '#ccc';
                overviewData[i].label = undefined;
            }

            var overviewPlot = $.plot(overviewPlaceholder, overviewData, {
                series: {
                    lines: {
                        show: true,
                        lineWidth: 1
                    },
                    shadowSize: 0,
                    points: {
                        show: false
                    }
                },
                xaxis: {
                    mode: "time"
                },
                yaxis: {},
                legend: {
                    show: false
                },
                grid: {
                    hoverable: false
                },
                rangeselection: {
                    color: '#999',
                    enabled: true,
                    start: detailPlot.getData()[0].data[0][0],
                    end: detailPlot.getData()[0].data[detailPlot.getData()[0].data.length - 100][0],
                    callback: rangeselectionCallback
                }
            });

            // Since the canvas is redrawn after every interaction, we have to manually set the selection range (if it exists)
            if (currentSelection.min !== undefined && currentSelection.max !== undefined) {
                var xaxis = detailPlot.getAxes().xaxis;
                xaxis.options.min = currentSelection.min;
                xaxis.options.max = currentSelection.max;
                detailPlot.setupGrid();
                detailPlot.draw();

                overviewPlot.getOptions().rangeselection.start = currentSelection.min;
                overviewPlot.getOptions().rangeselection.end = currentSelection.max;
                overviewPlot.setupGrid();
                overviewPlot.draw();
            }

            // Show current value(s) in tooltip
            if ($('#tooltip').length == 0) {
                $('

').css({
                    position: 'absolute',
                    display: 'none',
                    border: '1px solid #fdd',
                    padding: '2px',
                    'background-color': '#fee',
                    opacity: 0.80
                }).appendTo('body');
            }

            var tooltipContainer = $('#tooltip');
            var tooltipContent = $('#tooltip ul');

            // add empty entry for each time series
            tooltipContent.empty();
            for (var i = 0; i < plotdata.length; i++) {
                tooltipContent.append('
' + plotdata[i].label + ':
');
            }

            var updateTooltipTimeout = null;
            var latestPosition = null;

            function updateTooltip() {
                updateTooltipTimeout = null;
                var pos = latestPosition;
                var axes = detailPlot.getAxes();
                if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
                    pos.y < axes.yaxis.min || pos.y > axes.yaxis.max) {
                    tooltipContainer.hide('slow');
                    return;
                }

                var seriesIndex, dataPointInSeries, dataset = plotdata;

                // Iterate of each time series ('seriesIndex')
                var yMax;
                for (seriesIndex = 0; seriesIndex < dataset.length; ++seriesIndex) {
                    var series = dataset[seriesIndex];

                    // Find the nearest points, x-wise
                    for (dataPointInSeries = 0; series.data.length; ++dataPointInSeries) {
                        if (series.data[dataPointInSeries][0] > pos.x) {
                            break;
                        }
                    }

                    // Now interpolate
                    var y,
                        p1 = series.data[dataPointInSeries - 1],
                        p2 = series.data[dataPointInSeries];

                    if (p1 == null) {
                        y = p2[1];
                    } else if (p2 == null) {
                        y = p1[1];
                    } else {
                        y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);
                    }

                    // Set the correct value in the tooltip
                    if ($.isNumeric(y)) {
                        var toolTipItem = tooltipContent.find('li').eq(seriesIndex);
                        var text = toolTipItem.text();
                        toolTipItem.text(text.replace(/:.*/, ': ' + y.toFixed(2)));
                    }

                    if (y > yMax) {
                        yMax = y;
                    }
                }

                // Tooltip position
                tooltipContainer.css({
                    top: pos.pageY,
                    left: pos.pageX
                });

                // Current time as tooltip title
                $('#tooltip-title').empty();
                $('#tooltip-title').append(new Date(pos.x - (1000 * 60 * 60 * 2)));

                // Show tooltip
                tooltipContainer.show('slow');
            };

            detailPlaceholder.bind('plothover', function (event, pos, item) {
                latestPosition = pos;
                if (!updateTooltipTimeout) {
                    updateTooltipTimeout = setTimeout(updateTooltip, 400);
                }
            });
        };

        updatePlot();
    });
});

// Prepare data -------------------------------------------------------------------------------------------
var formatDate = function (date) {
    // requires moment.js
    return moment.utc(new Date(date)).format('ddd, YYYY MMM DD HH:mm');
};

var convertDataForFlot = function (data) {
    var flotdata = [];
    flotdata.push(mapTimeSeries(data, 'WA', 'outside', colors[0]));
    flotdata.push(mapTimeSeries(data, 'Z2', '2nd floor', colors[1]));
    flotdata.push(mapTimeSeries(data, 'Z3', '1st floor (work)', colors[2]));
    flotdata.push(mapTimeSeries(data, 'Z4', '1st floor (bathroom)', colors[3]));
    flotdata.push(mapTimeSeries(data, 'Z5', '1st floor (bedroom)', colors[4]));
    flotdata.push(mapTimeSeries(data, 'Z6', 'ground floor', colors[5]));
    return flotdata;
};

var mapTimeSeries = function (data, sensorName, label, col) {
    var series = [];
    for (var i = 0; i < data.length; i++) {
        if (data[i].sensorName === sensorName) {
            var mDate = moment(data[i].timestamp + ' +02:00', 'YYYY-MM-DD HH:mm:ss ZZ');
            mDate.add(2, 'hours'); // still don't understand why this is really necessary.
            var millis = new Date(mDate.unix()) * 1000;
            series.push([millis, data[i].degreeCelsius]);
        }
    }
    return {
        data: series,
        label: label,
        color: col
    };
};
<commit_msg>Added panning to detailPlot. Temp. exclude of tooltip.<commit_after>var colors = {
    0: "lightgray",
    1: "#edc240",
    2: "#afd8f8",
    3: "#cb4b4b",
    4: "#4da74d",
    5: "#9440ed",
    6: "rgb(189, 155, 51)",
    7: "rgb(140,172,198)"
};

$(function () {
    getAll(function (rawdata) {

        var data = convertDataForFlot(rawdata);

        // Legend -------------------------------------------------------------
        var legendContainer = $('#detail-legend');
        $.each(data, function (key, val) {
            legendContainer.append("
<input type='checkbox' name='" + key + "' checked='checked' id='id" + key + "'></input>" +
                "

" +
                "" + val.label + "");
        });

        legendContainer.find("input").click(updatePlot);

        var currentSelection = {
            min: undefined,
            max: undefined
        };

        // Main plotting function ---------------------------------------------
        function updatePlot() {

            var plotdata = [];

            legendContainer.find('input:checked').each(function () {
                var key = $(this).attr('name');
                if (key && data[key]) {
                    plotdata.push(data[key])
                }
            });

            var rangeselectionCallback = function (o) {
                var xaxis = detailPlot.getAxes().xaxis;
                xaxis.options.min = o.start;
                xaxis.options.max = o.end;
                detailPlot.setupGrid();
                detailPlot.draw();

                currentSelection.min = o.start;
                currentSelection.max = o.end;
            };

            var detailPlaceholder = $('#detail-placeholder');
            var detailPlot = $.plot(detailPlaceholder, plotdata, {
                xaxis: {
                    mode: 'time'
                },
                yaxis: {
                    panRange: false
                },
                series: {
                    lines: {
                        show: true
                    },
                    points: {
                        show: false
                    }
                },
                legend: {
                    show: false // Note: The legend is configured manually (see legendContainer)
                },
                grid: {
                    hoverable: true,
                    clickable: true,
                    autoHighlight: false
                },
                crosshair: {
                    mode: 'x'
                },
                pan: {
                    interactive: true
                }
            });

            var overviewPlaceholder = $('#overview-placeholder');
            var overviewData = $.extend(true, [], plotdata);
            for (var i = 0; i < overviewData.length; i++) {
                overviewData[i].color = '#ccc';
                overviewData[i].label = undefined;
            }

            var overviewPlot = $.plot(overviewPlaceholder, overviewData, {
                series: {
                    lines: {
                        show: true,
                        lineWidth: 1
                    },
                    shadowSize: 0,
                    points: {
                        show: false
                    }
                },
                xaxis: {
                    mode: "time"
                },
                yaxis: {},
                legend: {
                    show: false
                },
                grid: {
                    hoverable: false
                },
                rangeselection: {
                    color: '#999',
                    enabled: true,
                    start: detailPlot.getData()[0].data[0][0],
                    end: detailPlot.getData()[0].data[detailPlot.getData()[0].data.length - 100][0],
                    callback: rangeselectionCallback
                }
            });

            // Since the canvas is redrawn after every interaction, we have to manually set the selection range (if it exists)
            if (currentSelection.min !== undefined && currentSelection.max !== undefined) {
                var xaxis = detailPlot.getAxes().xaxis;
                xaxis.options.min = currentSelection.min;
                xaxis.options.max = currentSelection.max;
                detailPlot.setupGrid();
                detailPlot.draw();

                overviewPlot.getOptions().rangeselection.start = currentSelection.min;
                overviewPlot.getOptions().rangeselection.end = currentSelection.max;
                overviewPlot.setupGrid();
                overviewPlot.draw();
            }

            // Show current value(s) in tooltip
            if ($('#tooltip').length == 0) {
                $('

').css({
                    position: 'absolute',
                    display: 'none',
                    border: '1px solid #fdd',
                    padding: '2px',
                    'background-color': '#fee',
                    opacity: 0.80
                }).appendTo('body');
            }

            var tooltipContainer = $('#tooltip');
            var tooltipContent = $('#tooltip ul');

            // add empty entry for each time series
            tooltipContent.empty();
            for (var i = 0; i < plotdata.length; i++) {
                tooltipContent.append('
' + plotdata[i].label + ':
');
            }

            var updateTooltipTimeout = null;
            var latestPosition = null;

            function updateTooltip() {
                updateTooltipTimeout = null;
                var pos = latestPosition;
                var axes = detailPlot.getAxes();
                if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
                    pos.y < axes.yaxis.min || pos.y > axes.yaxis.max) {
                    tooltipContainer.hide('slow');
                    return;
                }

                var seriesIndex, dataPointInSeries, dataset = plotdata;

                // Iterate of each time series ('seriesIndex')
                var yMax;
                for (seriesIndex = 0; seriesIndex < dataset.length; ++seriesIndex) {
                    var series = dataset[seriesIndex];

                    // Find the nearest points, x-wise
                    for (dataPointInSeries = 0; series.data.length; ++dataPointInSeries) {
                        if (series.data[dataPointInSeries][0] > pos.x) {
                            break;
                        }
                    }

                    // Now interpolate
                    var y,
                        p1 = series.data[dataPointInSeries - 1],
                        p2 = series.data[dataPointInSeries];

                    if (p1 == null) {
                        y = p2[1];
                    } else if (p2 == null) {
                        y = p1[1];
                    } else {
                        y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);
                    }

                    // Set the correct value in the tooltip
                    if ($.isNumeric(y)) {
                        var toolTipItem = tooltipContent.find('li').eq(seriesIndex);
                        var text = toolTipItem.text();
                        toolTipItem.text(text.replace(/:.*/, ': ' + y.toFixed(2)));
                    }

                    if (y > yMax) {
                        yMax = y;
                    }
                }

                // Tooltip position
                tooltipContainer.css({
                    top: pos.pageY,
                    left: pos.pageX
                });

                // Current time as tooltip title
                $('#tooltip-title').empty();
                $('#tooltip-title').append(new Date(pos.x - (1000 * 60 * 60 * 2)));

                // Show tooltip
                tooltipContainer.show('slow');
            };

            //            detailPlaceholder.bind('plothover', function (event, pos, item) {
            //                latestPosition = pos;
            //                if (!updateTooltipTimeout) {
            //                    updateTooltipTimeout = setTimeout(updateTooltip, 400);
            //                }
            //            });

            function clampOverViewPlot(value) {
                overviewMin = overviewPlot.getAxes().xaxis.min;
                overviewMax = overviewPlot.getAxes().xaxis.max;
                return clamp(overviewMin, value, overviewMax);
            };

            detailPlaceholder.bind('plotpan', function (event, plot) {

                currentSelection.min = clampOverViewPlot(detailPlot.getAxes().xaxis.min);
                currentSelection.max = clampOverViewPlot(detailPlot.getAxes().xaxis.max);
                overviewPlot.setSelection(currentSelection.min, currentSelection.max);
            });

        };

        updatePlot();
    });
});

function clamp(min, value, max) {
    return value < min ? min : (value > max ? max : value);
};

// Prepare data -------------------------------------------------------------------------------------------
var formatDate = function (date) {
    // requires moment.js
    return moment.utc(new Date(date)).format('ddd, YYYY MMM DD HH:mm');
};

var convertDataForFlot = function (data) {
    var flotdata = [];
    flotdata.push(mapTimeSeries(data, 'WA', 'outside', colors[0]));
    flotdata.push(mapTimeSeries(data, 'Z2', '2nd floor', colors[1]));
    flotdata.push(mapTimeSeries(data, 'Z3', '1st floor (work)', colors[2]));
    flotdata.push(mapTimeSeries(data, 'Z4', '1st floor (bathroom)', colors[3]));
    flotdata.push(mapTimeSeries(data, 'Z5', '1st floor (bedroom)', colors[4]));
    flotdata.push(mapTimeSeries(data, 'Z6', 'ground floor', colors[5]));
    return flotdata;
};

var mapTimeSeries = function (data, sensorName, label, col) {
    var series = [];
    for (var i = 0; i < data.length; i++) {
        if (data[i].sensorName === sensorName) {
            var mDate = moment(data[i].timestamp + ' +02:00', 'YYYY-MM-DD HH:mm:ss ZZ');
            mDate.add(2, 'hours'); // still don't understand why this is really necessary.
            var millis = new Date(mDate.unix()) * 1000;
            series.push([millis, data[i].degreeCelsius]);
        }
    }
    return {
        data: series,
        label: label,
        color: col
    };
};
<|endoftext|>


<commit_before>/*global moment: false*/
function updateClock() {
  var now = moment();
  $('#day').text(now.format('dddd, Do MMMM YYYY'));
  $('#time').text(now.format('HH:mm'));
}

function timedUpdate() {
  updateClock();
  // update other information
  setTimeout(timedUpdate, 1000);
}

$(function () {
  timedUpdate();
  var plot = new Dygraph('beam-plot', 'beam.csv', {
    labels: ['Date', 'Primary Beam Intensity (a.u.)']
  });
});
<commit_msg>specify plot<commit_after>/*global moment: false*/
function updateClock() {
  var now = moment();
  $('#day').text(now.format('dddd, Do MMMM YYYY'));
  $('#time').text(now.format('HH:mm'));
}

function timedUpdate() {
  updateClock();
  // update other information
  setTimeout(timedUpdate, 1000);
}

$(function () {
  timedUpdate();
  var plot = new Dygraph('beam-plot', 'raw.csv', {
    labels: ['Date', 'Primary Beam Intensity (a.u.)'],
    // ylabel: 'Temperature (F)',
    legend: 'always',
    height: 150,
    width: 800
  });
});
<|endoftext|>