<commit_before><h2 data-intro="Scopri i posts dei membri di PAC. A presto ci saranno posts anche da altre communities.">
    Post dalla community di PAC</h2>
<hr>
<div id="feedapp">
  <div id="dashboard_div" class="row">
    <div class="col-md-3">
      <p>Usa lo slider sulla destra per filtrare i post. Alternativamente, 
      clicca su dei giorni specifici nel grafico per mostare tutti i post del giorno.
      </p>
      <p>
        Il sistema mostra 50 post alla volta e gli ultimi 20 annunci di lavoro.
      </p>
    </div>
    <div class="col-md-9">
      <i id="spinner" class="fa fa-spinner fa-pulse fa-3x fa-fw"></i>
      <div class="row">
        <div id="chart_div" data-intro="Questo grafico mostra tutti i post della community nel tempo."></div>
      </div>
      <div class="row">
        <div id="filter_div" data-intro="Usa lo slider per trovare i post più vecchi."></div>
      </div>
    </div>
  </div>

  <br>
  <hr>

  <div class="row">
      <div class="col-lg-12">
        <h4> Post </h4>
          <post-display v-if="sources_ready" :filter="{}" :sources="sources"></post-display>
        </div>
      </div>
  </div>
</div>


<% content_for :scripts do %>

<script type="text/x-template" id="post">
  <div class="card post">
    <img v-if="post.picture"
         v-bind:src="post.picture" 
         v-bind:alt="post.alt"
         class="card-img-top"></img>
    <div class="card-block">
      <p class="card-text" style="word-wrap: break-word;">{{ text }}</p>
    </div>
    <div class="card-footer text-muted text-right">
      {{author_name}} - {{ time }} - 
      {{post.source.name}} <img v-bind:src="post.source.icon_link" />
    </div>
  </div>
</script>

<script type="text/x-template" id="postDisplay">
  <div class="cont">
    <post v-for="p in posts" :post="p"></post>
  </div>
</script>

<style>
.card {
  width: 250px;
  display: inline-block;
  height: 400px;
  overflow: hidden;
  margin-right: 10px;
}

.card-footer {
  height: 80px;
  position:absolute;
  bottom:0;
  font-size: 13px;
}

.card-img-top{
   width:100%;
   height:100px;
   object-fit: cover;
}
</style>

<script type="text/javascript">

  /* Renders the filters
     emits filtersChanged event
   */
  Vue.component('filters', {

  })

  /* Renders a single post*/
  Vue.component('post', {
    template: '#post',
    props: {
      post: Object
    },
    computed: {
      text: function(){
        var content = this.post.content || "";
        var name = this.post.name ? this.post.name + " - " : "";
        return name + content;
      },
      time: function(){
        return moment(this.post.created_at).format("L LT");
      },
      author_name: function(){
        var name = this.post.author_name.split(" ");
        var first_name = name.shift();
        return first_name[0] + ". " + name.join(" ");
      }
    }
  });

  /* Fetches and displays the posts
     given some filters
  */
  Vue.component('postDisplay', {
    template: '#postDisplay',
    props: {
      filter: Object,
      sources: Object
    },
    components: {
      'waterfall': Waterfall.waterfall,
      'waterfall-slot': Waterfall.waterfallSlot
    },
    data: function () {
      return { posts: []}
    },
    mounted: function() {
      this.getPosts(this.filter);
    },
    methods: {
      getPosts: function(filter){
        var that = this;
        $.ajax({
        url: '/feed/posts.json',
        success: function(res) {    
          res = res.map(function(a){a['source'] = that.sources[a['source_id']]; return a;});
          that.posts = res;
        }
      });
      }
    }
  })

  /* Main app 
     Contains both filters and postDisplay
     listens to events from filters, and stores the last version in data
     the filters are then passed to postDisplay as props
  */
  var feed_app = new Vue({
    el: '#feedapp',
    data: {
      sources: {}
    },
    mounted: function(){
      var that = this;
      $.ajax({
        url: '/feed/sources.json',
        success: function(res) {
          that.sources = res;
        }
      });
    },
    computed: {
      sources_ready: function(){
        return Object.keys(this.sources).length > 0;
      }
    }
  });

</script>

<script type="text/javascript">
  // Set a callback to run when the Google Visualization API is loaded.
  google.charts.setOnLoadCallback(loadChart);

  function loadChart() {
    $('#spinner').show();
    var dataRequest = $.ajax({url: "/feed/data", dataType: "json"});

    dataRequest.fail(function(error){
      console.error(error)
    });

    dataRequest.done(function(data){
      drawChart(data);
    });
  }

  function drawChart(chartData) {
    // Create the data table.
    var data = new google.visualization.DataTable(chartData);

    var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div'));

    var today = new Date();
    var last_sixty = new Date(today.getTime() - (60 * 60 * 24 * 60 * 1000));
    var timeSlider = new google.visualization.ControlWrapper({
      'controlType': 'ChartRangeFilter',
      'containerId': 'filter_div',
      'options': {
        'filterColumnIndex': 0,
        ui: {
          chartOptions: {
            height: 50,
            chartArea: {
              width: '80%'
            }
          },
          chartView: {
            columns: [0, 1]
          }
        }
      },
      'state': {
        'range': {
          'start': last_sixty,
          'end': today
        }
      }
    });

    var chart = new google.visualization.ChartWrapper({
      chartType: 'LineChart',
      containerId: 'chart_div',
      options: {
        curveType: 'function',
        legend: 'none',
        vAxis: {
          viewWindow: {
            min: 0
          }
        },
        series: {
          0: {
            color: '#1B5E20'
          }
        }
      }
    });

    google.visualization.events.addListener(timeSlider, 'statechange', selectHandler);

    var timeout = null;
    function selectHandler(e) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      timeout = setTimeout(applySlider, 1000);
    }

    function applySlider() {
      var range = timeSlider.getState().range;
      var start = range.start.getTime();
      var end = range.end.getTime();

      reloadPosts(start, end);
    }

    function reloadPosts(start, end) {
      $.ajax({
        type: 'GET',
        url: '/feed/posts',
        data: {
          'start': start,
          'end': end
        }
      }).done(function (data) {
        $('#posts-view').html(data);
      }).fail(function (error) {
        console.error("reloadPosts failed");
        console.error(error);
      })
    }

    dashboard.bind(timeSlider, chart);
    dashboard.draw(data);
    $('#spinner').hide();
  }

  $(window).resize(function () {
    drawChart();
  });
</script>
<% end %><commit_msg>a stupid commit<commit_after><h2 data-intro="Scopri i posts dei membri di PAC. A presto ci saranno posts anche da altre communities.">
    Post dalla community di PAC</h2>
<hr>
<div id="feedapp">
  <div id="dashboard_div" class="row">
    <div class="col-md-3">
      <p>FILTRI</p>
    </div>
    <div class="col-md-9">
      <i id="spinner" class="fa fa-spinner fa-pulse fa-3x fa-fw"></i>
      <div class="row" style="display: none;">
        <div id="chart_div"></div>
      </div>
      <div class="row">
        <div id="filter_div" data-intro="Usa lo slider per trovare i post più vecchi."></div>
      </div>
    </div>
  </div>

  <br>
  <hr>

  <div class="row">
      <div class="col-lg-12">
        <h4> Post </h4>
          <post-display v-if="sources_ready" :filter="{}" :sources="sources"></post-display>
        </div>
      </div>
  </div>
</div>


<% content_for :scripts do %>

<script type="text/x-template" id="post">
  <div class="card post">
    <img v-if="post.picture"
         v-bind:src="post.picture" 
         v-bind:alt="post.alt"
         class="card-img-top"></img>
    <div class="card-block">
      <p class="card-text" style="word-wrap: break-word;">{{ text }}</p>
    </div>
    <div class="card-footer text-muted text-right">
      {{author_name}}
      <br>
      <img v-bind:src="post.source.icon_link" /> {{post.source.name}} 
      <br>
      {{ time }}
    </div>
  </div>
</script>

<script type="text/x-template" id="postDisplay">
  <div class="cont">
    <post v-for="p in posts" :post="p"></post>
  </div>
</script>

<style>
.card {
  width: 250px;
  display: inline-block;
  height: 400px;
  overflow: hidden;
  margin-right: 10px;
}

.card-footer {
  height: 80px;
  width:100%;
  position:absolute;
  bottom:0;
  font-size: 13px;
}

.card-img-top{
   width:100%;
   height:100px;
   object-fit: cover;
}
</style>

<script type="text/javascript">

  /* Renders the filters
     emits filtersChanged event
   */
  Vue.component('filters', {

  })

  /* Renders a single post*/
  Vue.component('post', {
    template: '#post',
    props: {
      post: Object
    },
    computed: {
      text: function(){
        var content = this.post.content || "";
        var name = this.post.name ? this.post.name + " - " : "";
        return name + content;
      },
      time: function(){
        return moment(this.post.created_at).format("L LT");
      },
      author_name: function(){
        var name = this.post.author_name.split(" ");
        var first_name = name.shift();
        return first_name[0] + ". " + name.join(" ");
      }
    }
  });

  /* Fetches and displays the posts
     given some filters
  */
  Vue.component('postDisplay', {
    template: '#postDisplay',
    props: {
      filter: Object,
      sources: Object
    },
    components: {
      'waterfall': Waterfall.waterfall,
      'waterfall-slot': Waterfall.waterfallSlot
    },
    data: function () {
      return { posts: []}
    },
    mounted: function() {
      this.getPosts(this.filter);
    },
    methods: {
      getPosts: function(filter){
        var that = this;
        $.ajax({
        url: '/feed/posts.json',
        success: function(res) {    
          res = res.map(function(a){a['source'] = that.sources[a['source_id']]; return a;});
          that.posts = res;
        }
      });
      }
    }
  })

  /* Main app 
     Contains both filters and postDisplay
     listens to events from filters, and stores the last version in data
     the filters are then passed to postDisplay as props
  */
  var feed_app = new Vue({
    el: '#feedapp',
    data: {
      sources: {}
    },
    mounted: function(){
      var that = this;
      $.ajax({
        url: '/feed/sources.json',
        success: function(res) {
          that.sources = res;
        }
      });
    },
    computed: {
      sources_ready: function(){
        return Object.keys(this.sources).length > 0;
      }
    }
  });

</script>

<script type="text/javascript">
  // Set a callback to run when the Google Visualization API is loaded.
  google.charts.setOnLoadCallback(loadChart);

  function loadChart() {
    $('#spinner').show();
    var dataRequest = $.ajax({url: "/feed/data", dataType: "json"});

    dataRequest.fail(function(error){
      console.error(error)
    });

    dataRequest.done(function(data){
      drawChart(data);
    });
  }

  function drawChart(chartData) {
    // Create the data table.
    var data = new google.visualization.DataTable(chartData);

    var dashboard = new google.visualization.Dashboard(document.getElementById('dashboard_div'));

    var today = new Date();
    var last_sixty = new Date(today.getTime() - (60 * 60 * 24 * 60 * 1000));
    var timeSlider = new google.visualization.ControlWrapper({
      'controlType': 'ChartRangeFilter',
      'containerId': 'filter_div',
      'options': {
        'filterColumnIndex': 0,
        ui: {
          chartOptions: {
            height: 50,
            chartArea: {
              width: '80%'
            }
          },
          chartView: {
            columns: [0, 1]
          }
        }
      },
      'state': {
        'range': {
          'start': last_sixty,
          'end': today
        }
      }
    });

    var chart = new google.visualization.ChartWrapper({
      chartType: 'LineChart',
      containerId: 'chart_div',
      options: {
        curveType: 'function',
        legend: 'none',
        vAxis: {
          viewWindow: {
            min: 0
          }
        },
        series: {
          0: {
            color: '#1B5E20'
          }
        }
      }
    });

    google.visualization.events.addListener(timeSlider, 'statechange', selectHandler);

    var timeout = null;
    function selectHandler(e) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      timeout = setTimeout(applySlider, 1000);
    }

    function applySlider() {
      var range = timeSlider.getState().range;
      var start = range.start.getTime();
      var end = range.end.getTime();

      reloadPosts(start, end);
    }

    function reloadPosts(start, end) {
      $.ajax({
        type: 'GET',
        url: '/feed/posts',
        data: {
          'start': start,
          'end': end
        }
      }).done(function (data) {
        $('#posts-view').html(data);
      }).fail(function (error) {
        console.error("reloadPosts failed");
        console.error(error);
      })
    }

    dashboard.bind(timeSlider, chart);
    dashboard.draw(data);
    $('#spinner').hide();
  }

  $(window).resize(function () {
    drawChart();
  });
</script>
<% end %>
{'fraction_non_alphanumeric': 0.15826911677534083, 'fraction_numerical': 0.009262003556609366, 'mean_word_length': 2.0864395152069517, 'pattern_counts': {'":': 0, '<': 129, '<?xml version=': 0, '>': 131, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1065205', 'n_tokens_mistral': 4475, 'n_tokens_neox': 4310, 'n_words': 981}