<commit_before>$(document).bind("mobileinit", function () {
    $.mobile.ajaxEnabled = false;
});

$(document).ready(function(){
  if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
    alert('There is a problem, please contact us at contact@eslam.me');
  }

  //Open all external links in the browser
  $('a[href^=http]').click(function(e){
      e.preventDefault();
      var activity = new MozActivity({
        name: "view",
        data: {
          type: "url",
          url: $(this).attr("href")
        }
      });
   });

  //Get the image of the email from gravatar
  $('#email').on('input', function() {
      $('#contact img').attr('src', "http://www.gravatar.com/avatar/"+md5($(this).val())+"?s=200&d=monsterid");
  });

  //Button clicked
  $('#save, #save_no_img').on('click', function(event){
    //Stop form submittion
    event.preventDefault();

    var name = $('#name').val();
    var phone = $('#phone').val();
    var email = $('#email').val();
    var imgURL = $('#contact img').attr('src');

    if (!name || !phone) {
      alert('Name & Phone are required');
      return;
    }

    var data = {
      name: name,
      phone: phone,
      email: email,
      imgURL: imgURL
    };

    //Remove the image if could not download it
    if ($(this).attr('id') == 'save_no_img') {
      data.imgURL = null;
    }

    //Save the data
    saveContact(data);
  });
});

function saveContact(data, blob){
  var person = new mozContact();
  person.name  = [data.name];
  person.givenName = [data.name];

  person.tel = [];
  person.tel[0]  = {type:['mobile'], value:data.phone};

  person.email = [];
  person.email[0]  = {type:['work'], value:data.email};

  //If there image try to download it then save the contact
  if (data.imgURL) {
    var oReq = new XMLHttpRequest();
    oReq.onload = function (e) {
      var arrayBufferView = new Uint8Array(this.response);
      person.photo  = [];
      person.photo[0] = new Blob([arrayBufferView], {type: 'image/png'});
      //Save the contact to contacts list
      savePerson(person);
    };

    //IF there was error loading the image display the other button for download
    oReq.onerror = function (e) {
      alert('Error could not get your contact image');
      $('#save_no_img').attr('style','display:table');
    }

    oReq.open("GET", data.imgURL, true);
    oReq.responseType = "arraybuffer";
    oReq.send();
  } else {
    savePerson(person)
  }
}

//Save the contact into contact list
function savePerson(person) {
  // save the new contact
  var saving = navigator.mozContacts.save(person);

  //Alert the user if the contact saved
  saving.onsuccess = function() {
    alert('New contact saved');
    init();
  };

  //Get if there was error and display the message
  saving.onerror = function(err) {
    console.log(err.target.error);
    if (err.target.error.message) {
     alert('Error: ' + err.target.error.message);
    } else if (err.target.error.name == 'PERMISSION_DENIED') {
     alert('Error: We need your permission to add new contact, please allow the app to add contacts');
    } else {
      alert('Error, Please contact us at contact@eslam.me');
    }
  };
}

//Reset the app after saving
function init() {
  $('#contact input').val(null);
  $('#save_no_img').hide();
  $('#contact img').attr('src', '/img/face.jpg');
}<commit_msg>v 0.5<commit_after>$(document).bind("mobileinit", function () {
    $.mobile.ajaxEnabled = false;
});

$(document).ready(function(){
  if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
    alert('There is a problem, please contact us at contact@eslam.me');
  }

  //Open all external links in the browser
  $('a[href^=http]').click(function(e){
      e.preventDefault();
      var activity = new MozActivity({
        name: "view",
        data: {
          type: "url",
          url: $(this).attr("href")
        }
      });
   });

  //Get the image of the email from gravatar
  $('#email').on('input', function() {
      $('#contact img').attr('src', "http://www.gravatar.com/avatar/"+md5($(this).val())+"?s=200&d=monsterid");
  });

  //Button clicked
  $('#save, #save_no_img').on('click', function(event){
    //Stop form submittion
    event.preventDefault();

    var name = $('#name').val();
    var phone = $('#phone').val();
    var email = $('#email').val();
    var imgURL = $('#contact img').attr('src');

    if (!name || !phone) {
      alert('Name & Phone are required');
      return;
    }

    var data = {
      name: name,
      phone: phone,
      email: email,
      imgURL: imgURL
    };

    //Remove the image if could not download it
    if ($(this).attr('id') == 'save_no_img') {
      data.imgURL = null;
    }

    //Save the data
    saveContact(data);
  });
});

function saveContact(data, blob){
  var person = new mozContact();
  person.name  = [data.name];
  person.givenName = [data.name];

  person.tel = [];
  person.tel[0]  = {type:['mobile'], value:data.phone};

  person.email = [];
  person.email[0]  = {type:['work'], value:data.email};

  //If there image try to download it then save the contact
  if (data.imgURL) {
    var oReq = new XMLHttpRequest();
    oReq.onload = function (e) {
      var arrayBufferView = new Uint8Array(this.response);
      person.photo  = [];
      person.photo[0] = new Blob([arrayBufferView], {type: 'image/png'});
      //Save the contact to contacts list
      savePerson(person);
    };

    //IF there was error loading the image display the other button for download
    oReq.onerror = function (e) {
      alert('Error could not get your contact image');
      $('#save_no_img').attr('style','display:table');
    }

    oReq.open("GET", data.imgURL, true);
    oReq.responseType = "arraybuffer";
    oReq.send();
  } else {
    savePerson(person)
  }
}

//Save the contact into contact list
function savePerson(person) {
  // save the new contact
  var saving = navigator.mozContacts.save(person);

  //Alert the user if the contact saved
  saving.onsuccess = function() {
    alert('New contact saved');
    init();
  };

  //Get if there was error and display the message
  saving.onerror = function(err) {
    if (err.target.error.name == 'PERMISSION_DENIED') {
     alert('Error: We need your permission to add new contact, please allow the app to add contacts');
    } else if (err.target.error.message) {
     alert('Error: ' + err.target.error.message);
    } else {
      alert('Error, Please contact us at contact@eslam.me');
    }
  };
}

//Reset the app after saving
function init() {
  $('#contact input').val(null);
  $('#save_no_img').hide();
  $('#contact img').attr('src', '/img/face.jpg');
}<|endoftext|>


<commit_before><commit_msg>added the routeProvider<commit_after>var app = angular.module('GalleryApp', ['ngRoute']);

app.config(function ($routeProvider) {
  $routeProvider
    .when('/', {
      controller: "HomeController",
      templateUrl: "views/home.html"
    })
    .when('/photos/:id', {
      controller: 'PhotoController',
      templateUrl: 'views/photo.html'
    })
    .otherwise({
      redirectTo: '/'
    });
});
<|endoftext|>


<commit_before>/*
 * Developed by Radu Puspana
 * Date August 2017
 * Version 1.0
 */

// module that handles the budget data using the module pattern
// IFEE creates a new scope. IFEE creates a closure for the vars/functions/objects
var budgetController = (function() {

    // some code

})();

// UI module manipulates the UI of the app
var uiController = (function() {

    // private object containing the class names used in index.html and style.css
    var prvDOMstrings = {
        inputType: ".add__type",
        inputDescription: ".add__description",
        inputValue: ".add__value",
        inputButton: ".add__btn"};

    return {
        // public method to retrieve and return all three field values as strings from the UI
        pblGetInput: function() {

            // return an object with all three fields values as strings from the UI
            return {
                // return "inc" or "exp" from the transaction type list
                type: document.querySelector(prvDOMstrings.inputType).value,

                // return the transaction description as string
                description: document.querySelector(prvDOMstrings.inputDescription).value,

                // return the transaction value as a string
                value: document.querySelector(prvDOMstrings.inputValue).value
            };
        },

        // public method for returning the object containing the class names in the index.html and style.css
        pblGetDOMstrings: function() {
            return prvDOMstrings;
        }
    }

})();

// App controller for communicating between the budgetController and the UIconroller
var controller = (function(budgetCtrl, UIctrl) {

    // private function to place the event listeners and the HTML tags' classes
    var prvSetupEventListeners = function() {

        // object containing the class names in the index.html and style.css
        var DOMstrings = uiController.pblGetDOMstrings();

        // register click event for the button with the tick sign
        document.querySelector(DOMstrings.inputButton).addEventListener("click", prvCtrlAddItem, false);

        // register Enter keypress event for the global object. Used only for the ENTER key
        document.getElementById("enterSum").addEventListener("keypress", function(event) {

            // use event.which to assure comptatibility with IE 9..11, Edge 14, UC Browser for Android 11.4
            // code 13 is returned when the "ENTER" key is pressed
            if (event.key === "Enter" || event.which === 13) { prvCtrlAddItem(); }

        }, false);
    };

    // private function for :
    // - retrieving all three user input field values
    var prvCtrlAddItem = function() {

        // get the field input data(expense or income)
        var userInput = uiController.pblGetInput();
        console.log(userInput);

        // add the item to the budget controller
        // add the new item to the UI
        // update the budget taking into account the expense/budget just entered
        // display the newly calculated budget on the UI
        console.log("You pressed enter and an item will be added to one of the tables and the budget will be updated")
    };

    return {
        initialiseVarsAndEvents: function() {
            console.log("App has started.");
            prvSetupEventListeners();
        }
    }

})(budgetController, uiController);

// Global execution scope
controller.initialiseVarsAndEvents();
<commit_msg>Add prvExpense constructor function<commit_after>/*
 * Developed by Radu Puspana
 * Date August 2017
 * Version 1.0
 */

// module that handles the budget data using the module pattern
// IFEE creates a new scope. IFEE creates a closure for the vars/functions/objects
var budgetController = (function() {

    // private Expense constructor
    var prvExpense = function(id, description, value) {
       this.id = id;
       this.description = description;
       this.value = value;
    };

})();

// UI module manipulates the UI of the app
var uiController = (function() {

    // private object containing the class names used in index.html and style.css
    var prvDOMstrings = {
        inputType: ".add__type",
        inputDescription: ".add__description",
        inputValue: ".add__value",
        inputButton: ".add__btn"};

    return {
        // public method to retrieve and return all three field values as strings from the UI
        pblGetInput: function() {

            // return an object with all three fields values as strings from the UI
            return {
                // return "inc" or "exp" from the transaction type list
                type: document.querySelector(prvDOMstrings.inputType).value,

                // return the transaction description as string
                description: document.querySelector(prvDOMstrings.inputDescription).value,

                // return the transaction value as a string
                value: document.querySelector(prvDOMstrings.inputValue).value
            };
        },

        // public method for returning the object containing the class names in the index.html and style.css
        pblGetDOMstrings: function() {
            return prvDOMstrings;
        }
    }

})();

// App controller for communicating between the budgetController and the UIconroller
var controller = (function(budgetCtrl, UIctrl) {

    // private function to place the event listeners and the HTML tags' classes
    var prvSetupEventListeners = function() {

        // object containing the class names in the index.html and style.css
        var DOMstrings = uiController.pblGetDOMstrings();

        // register click event for the button with the tick sign
        document.querySelector(DOMstrings.inputButton).addEventListener("click", prvCtrlAddItem, false);

        // register Enter keypress event for the global object. Used only for the ENTER key
        document.getElementById("enterSum").addEventListener("keypress", function(event) {

            // use event.which to assure comptatibility with IE 9..11, Edge 14, UC Browser for Android 11.4
            // code 13 is returned when the "ENTER" key is pressed
            if (event.key === "Enter" || event.which === 13) { prvCtrlAddItem(); }

        }, false);
    };

    // private function for :
    // - retrieving all three user input field values
    var prvCtrlAddItem = function() {

        // get the field input data(expense or income)
        var userInput = uiController.pblGetInput();
        console.log(userInput);

        // add the item to the budget controller
        // add the new item to the UI
        // update the budget taking into account the expense/budget just entered
        // display the newly calculated budget on the UI
        console.log("You pressed enter and an item will be added to one of the tables and the budget will be updated")
    };

    return {
        initialiseVarsAndEvents: function() {
            console.log("App has started.");
            prvSetupEventListeners();
        }
    }

})(budgetController, uiController);

// Global execution scope
controller.initialiseVarsAndEvents();
<|endoftext|>


<commit_before>var BankAccount = artifacts.require("../contracts/BankAccount");

contract('BankAccount', function(accounts) {
  var bank;

  beforeEach(function() {
    return BankAccount.new().then(function(instance) {
        bank = instance;
    });
  });

  it("Validate account deposit", function() {
    var amount = 100;
    var account = accounts[0];

    return bank.deposit(amount, {from: account}).then(function() {
      return bank.balanceOf.call(account);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), amount, "Expecting " + amount + " as the balance for account.");
    });

    done();
  });

  it("Validate account can't withdraw more than balance", function() {
    var account = accounts[0];
    var depositAmount = 50;
    var withdrawalAmount  = 100;

    return bank.deposit(depositAmount, {from: account}).then(function() {
      return bank.withdraw(withdrawalAmount, {from: account});
    }).then(function(){
      return bank.balanceOf.call(account);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), depositAmount, "Expecting " + depositAmount + " in the account.");
    });

    done();
  });

  it("Validate account withdrawal", function() {
    var account = accounts[0];
    var depositAmount = 100;
    var withdrawalAmount = 50;
    var expectedBalance = 50;

    return bank.deposit(depositAmount, {from: account}).then(function(){
      return bank.balanceOf.call(account);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), depositAmount, "Expecting initial value of " + depositAmount + " in the account.");
    }).then(function() {
      return bank.withdraw(withdrawalAmount, {from: account});
    }).then(function(){
      return bank.balanceOf.call(account);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), 1, "Expecting updated value of " + expectedBalance + " in the account.");
    });

    done();
  });
});<commit_msg>Fix failing test case<commit_after>var BankAccount = artifacts.require("../contracts/BankAccount");

contract('BankAccount', function(accounts) {
  var bank;

  beforeEach(function() {
    return BankAccount.new().then(function(instance) {
        bank = instance;
    });
  });

  it("Validate account deposit", function() {
    var amount = 100;
    var account = accounts[0];

    return bank.deposit(amount, {from: account}).then(function() {
      return bank.balanceOf.call(account);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), amount, "Expecting " + amount + " as the balance for account.");
    });

    done();
  });

  it("Validate account can't withdraw more than balance", function() {
    var account = accounts[0];
    var depositAmount = 50;
    var withdrawalAmount  = 100;

    return bank.deposit(depositAmount, {from: account}).then(function() {
      return bank.withdraw(withdrawalAmount, {from: account});
    }).then(function(){
      return bank.balanceOf.call(account);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), depositAmount, "Expecting " + depositAmount + " in the account.");
    });

    done();
  });

  it("Validate account withdrawal", function() {
    var account = accounts[0];
    var depositAmount = 100;
    var withdrawalAmount = 50;
    var expectedBalance = 50;

    return bank.deposit(depositAmount, {from: account}).then(function(){
      return bank.balanceOf.call(account);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), depositAmount, "Expecting initial value of " + depositAmount + " in the account.");
    }).then(function() {
      return bank.withdraw(withdrawalAmount, {from: account});
    }).then(function(){
      return bank.balanceOf.call(account);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), expectedBalance, "Expecting updated value of " + expectedBalance + " in the account.");
    });

    done();
  });
});<|endoftext|>


<commit_before>/**
 * New and Noteworthy Projects
 */

var $ = require('jquery');
var m = require('mithril');
var $osf = require('js/osfHelpers');

// CSS
require('css/quick-project-search-plugin.css');

// XHR config for apiserver connection
var xhrconfig = function(xhr) {
    xhr.withCredentials = true;
};

var NewAndNoteworthy = {
    controller: function() {
        var self = this;
        self.newAndNoteworthyNodes = m.prop([]);
        self.popularNodes = m.prop([]);
        self.contributorsMapping = {};
        self.SHOW_TOTAL = 5;

        // Load new and noteworthy nodes
        var newAndNoteworthyUrl = $osf.apiV2Url('nodes/' + window.contextVars.newAndNoteworthy + '/node_links/', {});
        var newAndNoteworthyPromise = m.request({method: 'GET', url: newAndNoteworthyUrl, config: xhrconfig});
        newAndNoteworthyPromise.then(function(result){
            var numNEW = Math.min(result.data.length, self.SHOW_TOTAL);
            for (var l=0; l < numNEW; l++) {
                self.newAndNoteworthyNodes().push(result.data[l]);
                self.fetchContributors(result.data[l]);
            }
        });

        // Load popular nodes
        var popularUrl = $osf.apiV2Url('nodes/' + window.contextVars.popular + '/node_links/', {});
        var popularPromise = m.request({method: 'GET', url: popularUrl, config: xhrconfig});
        popularPromise.then(function(result){
            var numPopular = Math.min(result.data.length, self.SHOW_TOTAL);
            for (var l=0; l < numPopular; l++) {
                self.popularNodes().push(result.data[l]);
                self.fetchContributors(result.data[l]);
            }
        });

        // Additional API call to fetch node link contributors
        self.fetchContributors = function(nodeLink) {
            var url = nodeLink.embeds.target_node.data.relationships.contributors.links.related.href;
            var promise = m.request({method: 'GET', url : url, config: xhrconfig});
            promise.then(function(result){
                var contribNames = [];
                result.data.forEach(function (contrib){
                    contribNames.push(contrib.embeds.users.data.attributes.family_name);
                });
                var numContrib = result.links.meta.total;
                var nodeId = nodeLink.id;
                self.contributorsMapping[nodeId] = [contribNames, numContrib];
            });
        };

        // Gets contrib family name for display
        self.getFamilyName = function(i, node) {
            return self.contributorsMapping[node.id][0][i];
        };

        // Returns name if one contrib, or adds et al if > 1
        self.contribNameFormat = function(node, number) {
            if (number === 1) {
                return self.getFamilyName(0, node);
            }
            else if (number === 2) {
                return self.getFamilyName(0, node) + ' and ' +
                    self.getFamilyName(1, node);
            }
            else if (number === 3) {
                return self.getFamilyName(0, node) + ', ' +
                    self.getFamilyName(1, node) + ', and ' +
                    self.getFamilyName(2, node);
            }
            else {
                return self.getFamilyName(0, node) + ', ' +
                    self.getFamilyName(1, node) + ', ' +
                    self.getFamilyName(2, node) + ' + ' + (number - 3);
            }
        };

        self.addToolTip = function(line) {
            var $line = $(line);
            if (line.offsetWidth < line.scrollWidth && !$line.attr('title')) {
                $line.attr('title', $line.text());
            }
        };
    },
    view : function(ctrl) {
        function nodeDisplay(node) {
            var description = node.embeds.target_node.data.attributes.description;

            return m('div.node-styling.noteworthy-spacing', {'class': 'row', onclick: function(){
                location.href = '/' + node.embeds.target_node.data.id;}
            },
                m('div', {'class': 'col-sm-12'},
                    m('h5.prevent-overflow', {onmouseover: function(){ctrl.addToolTip(this);}},
                        m('em', node.embeds.target_node.data.attributes.title)),
                    m('h5.prevent-overflow', {onmouseover: function(){ctrl.addToolTip(this);}},
                        description ?  description : m('p', {'class': 'blank-line'})),
                    m('h5.prevent-overflow', m('span', {'class': 'f-w-xl'}, 'Contributors: '),
                            m('span', ctrl.contribNameFormat(node, ctrl.contributorsMapping[node.id][1])))
                )
            );
        }

        function newAndNoteworthyProjectsTemplate () {
            return ctrl.newAndNoteworthyNodes().map(function(node){
                return nodeDisplay(node);
            });
        }

        function popularProjectsTemplate () {
            return ctrl.popularNodes().map(function(node){
                return nodeDisplay(node);
            });
        }

        function findMoreProjectsButton () {
            return m('a.btn.btn-default.m-v-lg', {type:'button', href:'/search'}, 'Find more projects with advanced search');
        }

        return m('div', {'class': 'container'}, [
            m('div', {'class': 'row'},
                m('div', {'class': 'col-sm-1'}),
                m('div', {'class': 'col-sm-11'}, m('h3', 'Discover Public Projects'))),

            m('div', {'class': 'row'},
                m('div', {'class': 'col-sm-10 col-sm-offset-1'},
                    m('div', {'class': 'col-sm-6 col-xs-12'}, m('h4', 'New and Noteworthy'), newAndNoteworthyProjectsTemplate()),
                    m('div', {'class': 'col-sm-6 col-xs-12'}, m('h4', 'Most Popular'), popularProjectsTemplate ())
            )),

            m('div', {'class': 'row'},
                m('div', {'class': 'col-sm-1'}),
                m('div.text-center', {'class': 'col-sm-10'}, findMoreProjectsButton()),
                m('div', {'class': 'col-sm-1'})

            )
        ]);
    }
};

module.exports = NewAndNoteworthy;

<commit_msg>Use bootstrap tooltip instead of browser default tooltip.<commit_after>/**
 * New and Noteworthy Projects
 */

var $ = require('jquery');
var m = require('mithril');
var $osf = require('js/osfHelpers');

// CSS
require('css/quick-project-search-plugin.css');

// XHR config for apiserver connection
var xhrconfig = function(xhr) {
    xhr.withCredentials = true;
};

var NewAndNoteworthy = {
    controller: function() {
        var self = this;
        self.newAndNoteworthyNodes = m.prop([]);
        self.popularNodes = m.prop([]);
        self.contributorsMapping = {};
        self.SHOW_TOTAL = 5;

        // Load new and noteworthy nodes
        var newAndNoteworthyUrl = $osf.apiV2Url('nodes/' + window.contextVars.newAndNoteworthy + '/node_links/', {});
        var newAndNoteworthyPromise = m.request({method: 'GET', url: newAndNoteworthyUrl, config: xhrconfig});
        newAndNoteworthyPromise.then(function(result){
            var numNEW = Math.min(result.data.length, self.SHOW_TOTAL);
            for (var l=0; l < numNEW; l++) {
                self.newAndNoteworthyNodes().push(result.data[l]);
                self.fetchContributors(result.data[l]);
            }
        });

        // Load popular nodes
        var popularUrl = $osf.apiV2Url('nodes/' + window.contextVars.popular + '/node_links/', {});
        var popularPromise = m.request({method: 'GET', url: popularUrl, config: xhrconfig});
        popularPromise.then(function(result){
            var numPopular = Math.min(result.data.length, self.SHOW_TOTAL);
            for (var l=0; l < numPopular; l++) {
                self.popularNodes().push(result.data[l]);
                self.fetchContributors(result.data[l]);
            }
        });

        // Additional API call to fetch node link contributors
        self.fetchContributors = function(nodeLink) {
            var url = nodeLink.embeds.target_node.data.relationships.contributors.links.related.href;
            var promise = m.request({method: 'GET', url : url, config: xhrconfig});
            promise.then(function(result){
                var contribNames = [];
                result.data.forEach(function (contrib){
                    contribNames.push(contrib.embeds.users.data.attributes.family_name);
                });
                var numContrib = result.links.meta.total;
                var nodeId = nodeLink.id;
                self.contributorsMapping[nodeId] = [contribNames, numContrib];
            });
        };

        // Gets contrib family name for display
        self.getFamilyName = function(i, node) {
            return self.contributorsMapping[node.id][0][i];
        };

        // Returns name if one contrib, or adds et al if > 1
        self.contribNameFormat = function(node, number) {
            if (number === 1) {
                return self.getFamilyName(0, node);
            }
            else if (number === 2) {
                return self.getFamilyName(0, node) + ' and ' +
                    self.getFamilyName(1, node);
            }
            else if (number === 3) {
                return self.getFamilyName(0, node) + ', ' +
                    self.getFamilyName(1, node) + ', and ' +
                    self.getFamilyName(2, node);
            }
            else {
                return self.getFamilyName(0, node) + ', ' +
                    self.getFamilyName(1, node) + ', ' +
                    self.getFamilyName(2, node) + ' + ' + (number - 3);
            }
        };

        self.addToolTip = function(line) {
            var $line = $(line);
            if (line.offsetWidth < line.scrollWidth && !$line.attr('title')) {
                $line.tooltip({
                    title: $line.text(),
                    placement: 'top'
                });
                $line.tooltip('show');
            }
        };
    },
    view : function(ctrl) {
        function nodeDisplay(node) {
            var description = node.embeds.target_node.data.attributes.description;

            return m('div.node-styling.noteworthy-spacing', {'class': 'row', onclick: function(){
                location.href = '/' + node.embeds.target_node.data.id;}
            },
                m('div', {'class': 'col-sm-12'},
                    m('h5.prevent-overflow', {onmouseover: function(){ctrl.addToolTip(this);}},
                        m('em', node.embeds.target_node.data.attributes.title)),
                    m('h5.prevent-overflow', {onmouseover: function(){ctrl.addToolTip(this);}},
                        description ?  description : m('p', {'class': 'blank-line'})),
                    m('h5.prevent-overflow',  {onmouseover: function(){ctrl.addToolTip(this);}},
                        m('span', {'class': 'f-w-xl'}, 'Contributors: '),
                            m('span', ctrl.contribNameFormat(node, ctrl.contributorsMapping[node.id][1])))
                )
            );
        }

        function newAndNoteworthyProjectsTemplate () {
            return ctrl.newAndNoteworthyNodes().map(function(node){
                return nodeDisplay(node);
            });
        }

        function popularProjectsTemplate () {
            return ctrl.popularNodes().map(function(node){
                return nodeDisplay(node);
            });
        }

        function findMoreProjectsButton () {
            return m('a.btn.btn-default.m-v-lg', {type:'button', href:'/search'}, 'Find more projects with advanced search');
        }

        return m('div', {'class': 'container'}, [
            m('div', {'class': 'row'},
                m('div', {'class': 'col-sm-1'}),
                m('div', {'class': 'col-sm-11'}, m('h3', 'Discover Public Projects'))),

            m('div', {'class': 'row'},
                m('div', {'class': 'col-sm-10 col-sm-offset-1'},
                    m('div', {'class': 'col-sm-6 col-xs-12'}, m('h4', 'New and Noteworthy'), newAndNoteworthyProjectsTemplate()),
                    m('div', {'class': 'col-sm-6 col-xs-12'}, m('h4', 'Most Popular'), popularProjectsTemplate ())
            )),

            m('div', {'class': 'row'},
                m('div', {'class': 'col-sm-1'}),
                m('div.text-center', {'class': 'col-sm-10'}, findMoreProjectsButton()),
                m('div', {'class': 'col-sm-1'})

            )
        ]);
    }
};

module.exports = NewAndNoteworthy;

<|endoftext|>


<commit_before>
/*
 * extend infowindow to serialize only the data we need
 */
_.extend(cdb.geo.ui.InfowindowModel.prototype, {
  toJSON: function() {
    return {
      fields: _.clone(this.attributes.fields),
      template_name: this.attributes.template_name
    };
  }
});

/**
 * extend gmaps layer for data serialization
 */
cdb.admin.GMapsBaseLayer = cdb.geo.GMapsBaseLayer.extend({

  parse: function(data) {
    var c = {};
    _.extend(c, data.options, {
      id: data.id,
      type: 'GMapsBase'
    });
    return c;
  },

  toJSON: function() {
    var c = _.clone(this.attributes);

    var d = {
      kind:  'gmapsbase',
      options: c,
      order: c.order
    };

    if(c.id !== undefined) {
      d.id = c.id;
    }
    return d;
  }

});
/**
 * extend plain layer for data serialization
 */
cdb.admin.PlainLayer= cdb.geo.PlainLayer.extend({

  parse: function(data) {
    var c = {};
    _.extend(c, data.options, {
      id: data.id,
      type: 'Plain'
    });
    return c;
  },

  toJSON: function() {
    var c = _.clone(this.attributes);

    var d = {
      kind:  'background',
      options: c,
      order: c.order
    };

    if(c.id !== undefined) {
      d.id = c.id;
    }
    return d;
  }

});

/**
 * extend tiled layer to adapt serialization
 */
cdb.admin.TileLayer = cdb.geo.TileLayer.extend({

  parse: function(data) {
    var c = {};
    _.extend(c, data.options, {
      id: data.id,
      type: 'Tiled'
    });
    return c;
  },

  toJSON: function() {
    var c = _.clone(this.attributes);

    var d = {
      kind:  'tiled',
      options: c,
      order: c.order
    };

    if(c.id !== undefined) {
      d.id = c.id;
    }
    return d;
  }

});

var attrHistory = function(model, attr) {

    model.MAX_HISTORY = 5;

    // variables needed to keep history state
    var attrHistory =  attr + '_history';
    var attrHistoryPos = attr + '_history_position'
    model[attrHistoryPos] = 0;

    // save history when attr changes
    var save = model['save' + attrHistory] = function(m, attrVal) {
      // If null, doesn't save anything
      if(attrVal == null) return;

      var h = model.attributes[attrHistory];
      h.push(attrVal);
      if(h.length > model.MAX_HISTORY)  {
        h.shift();
      }
      model.trigger('change:' + attrHistory, model, model.attributes[attrHistory]);
    }

    // to go foward and backward in history
    function moveHistory(d) {
      var h = model[attrHistoryPos] + d;
      // clamp
      model[attrHistoryPos] = Math.min(Math.max(0, h), model.attributes[attrHistory].length - 1);
      model.unbind('change:' + attr, save, model);
      var a = {};
      a[attr] =  model.attributes[attrHistory][model[attrHistoryPos]];
      model.set(a);
      model.bind('change:' + attr, save, model);
    }
    model['move' + attr + 'History'] = moveHistory;

    // bind changes
    model.bind('change:' + attr, save, model);
    model.bind('change:' + attrHistory, function() {
      model[attrHistoryPos] = model.get(attrHistory).length - 1;
    }, model);

    // create history list in the model if it does not exist
    if(!model.has(attrHistory)) {
      var a = {};
      a[attrHistory] = [];
      model.set(a, { silent: true });
    }
};

cdb.admin.CartoDBLayer = cdb.geo.CartoDBLayer.extend({

  MAX_HISTORY: 5,

  initialize: function() {
    this.set('use_server_style', true);
    attrHistory(this, 'tile_style');
    attrHistory(this, 'query');
    //this.bind('change:tile_style', this.saveStyle, this);
  },

  redoStyle: function() {
    this.movetile_styleHistory(1);
  },

  undoStyle: function() {
    this.movetile_styleHistory(-1);
  },

  redoQuery: function() {
    this.movequeryHistory(1);
  },

  undoQuery: function() {
    this.movequeryHistory(-1);
  },

  toJSON: function() {
    var c = _.clone(this.attributes);
    // remove api key
    if(c.extra_params) {
      c.extra_params = _.clone(this.attributes.extra_params);
      if(c.extra_params.api_key) {
        delete c.extra_params.api_key;
      }
      if(c.extra_params.map_key) {
        delete c.extra_params.map_key;
      }
    }

    var infowindow = c.infowindow;
    delete c.infowindow;
    var d = {
      kind: 'carto',
      options: c,
      order: c.order,
      infowindow: infowindow
    };
    if(c.id !== undefined) {
      d.id = c.id;
    }
    return d;
  },

  parse: function(data) {
    var c = {};

    // if api_key exist alread, set in params to not lose it
    if(data.options.extra_params && this.attributes && this.attributes.extra_params) {
      data.options.extra_params.map_key = this.attributes.extra_params.map_key;
    }

    _.extend(c, data.options, {
      id: data.id,
      type: 'CartoDB',
      infowindow: data.infowindow
    });

    return c;
  },

  sync: function(method, model, options) {
    var self = this;
    var s = this.get('extra_params');
    s.cache_killer = new Date().getTime();
    this.saveStyle(this, this.get('tile_style'), function() {
      Backbone.sync(method, model, options);
    });
  },

  save: function(attrs, opts) {
    opts = opts || {};
    if(attrs && attrs.tile_style) opts.wait = true;
    cdb.geo.CartoDBLayer.prototype.save.call(this, attrs, opts);
  },

  /**
   * save style to tiler end point
   * this method should be removed in thr future
   */
  saveStyle: function(model, st, done) {
    var self = this;
    var url = 'http://' + this.get('user_name') + "." + cdb.config.get("tiler_domain") + ':' + cdb.config.get("tiler_port") + '/tiles/' + this.get('table_name') + '/style'
    var api_key = this.get('extra_params').map_key;
    if(api_key) {
      url += '?map_key=' + api_key;
    }
    $.ajax({
      url: url,
      type: 'POST',
      crossOrigin: true,
      data:"style="+  encodeURIComponent(st),
      success: function() {
        done && done();
      },
      error: function() {
        self.trigger('error');
      }
    });
  }

});

cdb.admin.Layers = cdb.geo.Layers.extend({

  // the model class works here like a factory
  // depending of the kind of layer creates a
  // type of layer or other
  model: function(attrs, options) {
    var typeClass = {
      'Tiled': cdb.admin.TileLayer,
      'CartoDB': cdb.admin.CartoDBLayer,
      'Plain': cdb.admin.PlainLayer,
      'GMapsBase': cdb.admin.GMapsBaseLayer
    };
    var typeMap = {
      'Layer::Tiled': 'Tiled',
      'Layer::Carto': 'CartoDB',
      'Layer::Background': 'Plain',
      'tiled': 'Tiled',
      'carto': 'CartoDB',
      'background': 'Plain',
      'gmapsbase': 'GMapsBase'
    };

    return new typeClass[typeMap[attrs.kind]](attrs, options);
  },

  url: function() {
    return '/api/v1/maps/' +  this.map.id + '/layers';
  },

  parse: function(data) {
    return data.layers;
  },

  saveLayers: function() {
    this.each(function(l) { l.save(); });
  },

  /**
   * on reset order the layers so tiled layer are under cartodb layers
   */
  reset: function(models, options) {
    var sortOrder = {
      'Tiled': 0,
      'CartoDB': 1,
      'tiled': 0,
      'carto': 1
    };
    var sortModels = function(a, b) {
      return sortOrder[a.get('type')] - sortOrder[b.get('type')];
    };
    var sortRaw = function(a, b) {
      return sortOrder[a.kind] - sortOrder[b.kind];
    };

    if(_.size(models)) {
      // if is not a model use raw sort
      _(models).sort(models[0].get === undefined ? sortRaw : sortModels);
    }

    Backbone.Collection.prototype.reset.call(this, models, options);
  }

});

/**
 * this is a specialization of generic map prepared to hold two layers:
 *  - a base layer
 *  - a data layer which contains the table data
 *
 * cartodb only supports one data layer per map so this will change when
 * that changes
 */

cdb.admin.Map = cdb.geo.Map.extend({

  urlRoot: '/api/v1/maps',

  initialize: function() {
    this.constructor.__super__.initialize.apply(this);
    this.delayedSave = _.debounce(this.save, 1000);
    //this.autoSave();
    this.bind('change:id', this._fetchLayers, this);
    this.layers = new cdb.admin.Layers();
    this.layers.map = this;
    this.layers.bind('reset', this._layersChanged, this);
    this.layers.bind('add', this._layersChanged, this);
  },

  _layersChanged: function() {
    if(this.layers.size() >= 2) {
      this.set({ dataLayer: this.layers.at(1) });
    }
  },

  // fetch related layers
  _fetchLayers: function() {
    this.layers.fetch();
  },

  /**
   * link to a table
   */
  relatedTo: function(table) {
    this.table = table;
    this.table.bind('change:map_id', this._fetchOrCreate, this);
  },

  parse: function(data) {
    data.bounding_box_ne = JSON.parse(data.bounding_box_ne);
    data.bounding_box_sw = JSON.parse(data.bounding_box_sw);
    data.view_bounds_ne = JSON.parse(data.view_bounds_ne);
    data.view_bounds_sw = JSON.parse(data.view_bounds_sw);
    data.center = JSON.parse(data.center);
    return data;
  },

  _fetchOrCreate: function() {
    var self = this;
    var map_id = this.table.get('map_id');
    if(!map_id) {
      this.create();
    } else {
      this.set({ id: map_id });
      this.fetch({
        error: function() {
          cdb.log.info("creating map for table");
          self.create();
        }
      });
    }
  },

  /**
   * the first version of cartodb contains one single layer
   * per table with information.
   */
  addDataLayer: function(lyr) {
    this.addLayer(lyr);
    this.set({ dataLayer: lyr });
  },

  /**
   * create a new map. this is a helper to use from javascript command line
   */
  create: function() {
    this.unset('id');
    this.set({ table_id: this.table.id });
    this.save();
  },

  /**
   * enable save map each time the viewport changes
   * not working
   */
  autoSave: function() {
    this.bind('change:center', this.delayedSave);
    this.bind('change:zoom', this.delayedSave);
  },

  toJSON: function() {
    var c = _.clone(this.attributes);
    // data layer is a helper to work in local
    delete c.dataLayer;
    return c;
  }

});
<commit_msg>fixed sync for data layer.<commit_after>
/*
 * extend infowindow to serialize only the data we need
 */
_.extend(cdb.geo.ui.InfowindowModel.prototype, {
  toJSON: function() {
    return {
      fields: _.clone(this.attributes.fields),
      template_name: this.attributes.template_name
    };
  }
});

/**
 * extend gmaps layer for data serialization
 */
cdb.admin.GMapsBaseLayer = cdb.geo.GMapsBaseLayer.extend({

  parse: function(data) {
    var c = {};
    _.extend(c, data.options, {
      id: data.id,
      type: 'GMapsBase'
    });
    return c;
  },

  toJSON: function() {
    var c = _.clone(this.attributes);

    var d = {
      kind:  'gmapsbase',
      options: c,
      order: c.order
    };

    if(c.id !== undefined) {
      d.id = c.id;
    }
    return d;
  }

});
/**
 * extend plain layer for data serialization
 */
cdb.admin.PlainLayer= cdb.geo.PlainLayer.extend({

  parse: function(data) {
    var c = {};
    _.extend(c, data.options, {
      id: data.id,
      type: 'Plain'
    });
    return c;
  },

  toJSON: function() {
    var c = _.clone(this.attributes);

    var d = {
      kind:  'background',
      options: c,
      order: c.order
    };

    if(c.id !== undefined) {
      d.id = c.id;
    }
    return d;
  }

});

/**
 * extend tiled layer to adapt serialization
 */
cdb.admin.TileLayer = cdb.geo.TileLayer.extend({

  parse: function(data) {
    var c = {};
    _.extend(c, data.options, {
      id: data.id,
      type: 'Tiled'
    });
    return c;
  },

  toJSON: function() {
    var c = _.clone(this.attributes);

    var d = {
      kind:  'tiled',
      options: c,
      order: c.order
    };

    if(c.id !== undefined) {
      d.id = c.id;
    }
    return d;
  }

});

var attrHistory = function(model, attr) {

    model.MAX_HISTORY = 5;

    // variables needed to keep history state
    var attrHistory =  attr + '_history';
    var attrHistoryPos = attr + '_history_position'
    model[attrHistoryPos] = 0;

    // save history when attr changes
    var save = model['save' + attrHistory] = function(m, attrVal) {
      // If null, doesn't save anything
      if(attrVal == null) return;

      var h = model.attributes[attrHistory];
      h.push(attrVal);
      if(h.length > model.MAX_HISTORY)  {
        h.shift();
      }
      model.trigger('change:' + attrHistory, model, model.attributes[attrHistory]);
    }

    // to go foward and backward in history
    function moveHistory(d) {
      var h = model[attrHistoryPos] + d;
      // clamp
      model[attrHistoryPos] = Math.min(Math.max(0, h), model.attributes[attrHistory].length - 1);
      model.unbind('change:' + attr, save, model);
      var a = {};
      a[attr] =  model.attributes[attrHistory][model[attrHistoryPos]];
      model.set(a);
      model.bind('change:' + attr, save, model);
    }
    model['move' + attr + 'History'] = moveHistory;

    // bind changes
    model.bind('change:' + attr, save, model);
    model.bind('change:' + attrHistory, function() {
      model[attrHistoryPos] = model.get(attrHistory).length - 1;
    }, model);

    // create history list in the model if it does not exist
    if(!model.has(attrHistory)) {
      var a = {};
      a[attrHistory] = [];
      model.set(a, { silent: true });
    }
};

cdb.admin.CartoDBLayer = cdb.geo.CartoDBLayer.extend({

  MAX_HISTORY: 5,

  initialize: function() {
    this.set('use_server_style', true);
    attrHistory(this, 'tile_style');
    attrHistory(this, 'query');
    //this.bind('change:tile_style', this.saveStyle, this);
  },

  redoStyle: function() {
    this.movetile_styleHistory(1);
  },

  undoStyle: function() {
    this.movetile_styleHistory(-1);
  },

  redoQuery: function() {
    this.movequeryHistory(1);
  },

  undoQuery: function() {
    this.movequeryHistory(-1);
  },

  toJSON: function() {
    var c = _.clone(this.attributes);
    // remove api key
    if(c.extra_params) {
      c.extra_params = _.clone(this.attributes.extra_params);
      if(c.extra_params.api_key) {
        delete c.extra_params.api_key;
      }
      if(c.extra_params.map_key) {
        delete c.extra_params.map_key;
      }
    }

    var infowindow = c.infowindow;
    delete c.infowindow;
    var d = {
      kind: 'carto',
      options: c,
      order: c.order,
      infowindow: infowindow
    };
    if(c.id !== undefined) {
      d.id = c.id;
    }
    return d;
  },

  parse: function(data) {
    var c = {};

    // if api_key exist alread, set in params to not lose it
    if(data.options.extra_params && this.attributes && this.attributes.extra_params) {
      data.options.extra_params.map_key = this.attributes.extra_params.map_key;
    }

    _.extend(c, data.options, {
      id: data.id,
      type: 'CartoDB',
      infowindow: data.infowindow
    });

    return c;
  },

  sync: function(method, model, options) {
    var self = this;
    var s = this.get('extra_params');
    s.cache_killer = new Date().getTime();
    options.data = model.toJSON();
    this.saveStyle(this, this.get('tile_style'), function() {
      // dont pass the model to sync
      // the model data is stored in options.data because
      // it needs to be saved when sync is called (and not
      // after it)
      Backbone.sync(method, null, options);
    });
  },

  save: function(attrs, opts) {
    opts = opts || {};
    if(attrs && attrs.tile_style) opts.wait = true;
    cdb.geo.CartoDBLayer.prototype.save.call(this, attrs, opts);
  },

  /**
   * save style to tiler end point
   * this method should be removed in thr future
   */
  saveStyle: function(model, st, done) {
    var self = this;
    var url = 'http://' + this.get('user_name') + "." + cdb.config.get("tiler_domain") + ':' + cdb.config.get("tiler_port") + '/tiles/' + this.get('table_name') + '/style'
    var api_key = this.get('extra_params').map_key;
    if(api_key) {
      url += '?map_key=' + api_key;
    }
    $.ajax({
      url: url,
      type: 'POST',
      crossOrigin: true,
      data:"style="+  encodeURIComponent(st),
      success: function() {
        done && done();
      },
      error: function() {
        self.trigger('error');
      }
    });
  }

});

cdb.admin.Layers = cdb.geo.Layers.extend({

  // the model class works here like a factory
  // depending of the kind of layer creates a
  // type of layer or other
  model: function(attrs, options) {
    var typeClass = {
      'Tiled': cdb.admin.TileLayer,
      'CartoDB': cdb.admin.CartoDBLayer,
      'Plain': cdb.admin.PlainLayer,
      'GMapsBase': cdb.admin.GMapsBaseLayer
    };
    var typeMap = {
      'Layer::Tiled': 'Tiled',
      'Layer::Carto': 'CartoDB',
      'Layer::Background': 'Plain',
      'tiled': 'Tiled',
      'carto': 'CartoDB',
      'background': 'Plain',
      'gmapsbase': 'GMapsBase'
    };

    return new typeClass[typeMap[attrs.kind]](attrs, options);
  },

  url: function() {
    return '/api/v1/maps/' +  this.map.id + '/layers';
  },

  parse: function(data) {
    return data.layers;
  },

  saveLayers: function() {
    this.each(function(l) { l.save(); });
  },

  /**
   * on reset order the layers so tiled layer are under cartodb layers
   */
  reset: function(models, options) {
    var sortOrder = {
      'Tiled': 0,
      'CartoDB': 1,
      'tiled': 0,
      'carto': 1
    };
    var sortModels = function(a, b) {
      return sortOrder[a.get('type')] - sortOrder[b.get('type')];
    };
    var sortRaw = function(a, b) {
      return sortOrder[a.kind] - sortOrder[b.kind];
    };

    if(_.size(models)) {
      // if is not a model use raw sort
      _(models).sort(models[0].get === undefined ? sortRaw : sortModels);
    }

    Backbone.Collection.prototype.reset.call(this, models, options);
  }

});

/**
 * this is a specialization of generic map prepared to hold two layers:
 *  - a base layer
 *  - a data layer which contains the table data
 *
 * cartodb only supports one data layer per map so this will change when
 * that changes
 */

cdb.admin.Map = cdb.geo.Map.extend({

  urlRoot: '/api/v1/maps',

  initialize: function() {
    this.constructor.__super__.initialize.apply(this);
    this.delayedSave = _.debounce(this.save, 1000);
    //this.autoSave();
    this.bind('change:id', this._fetchLayers, this);
    this.layers = new cdb.admin.Layers();
    this.layers.map = this;
    this.layers.bind('reset', this._layersChanged, this);
    this.layers.bind('add', this._layersChanged, this);
  },

  _layersChanged: function() {
    if(this.layers.size() >= 2) {
      this.set({ dataLayer: this.layers.at(1) });
    }
  },

  // fetch related layers
  _fetchLayers: function() {
    this.layers.fetch();
  },

  /**
   * link to a table
   */
  relatedTo: function(table) {
    this.table = table;
    this.table.bind('change:map_id', this._fetchOrCreate, this);
  },

  parse: function(data) {
    data.bounding_box_ne = JSON.parse(data.bounding_box_ne);
    data.bounding_box_sw = JSON.parse(data.bounding_box_sw);
    data.view_bounds_ne = JSON.parse(data.view_bounds_ne);
    data.view_bounds_sw = JSON.parse(data.view_bounds_sw);
    data.center = JSON.parse(data.center);
    return data;
  },

  _fetchOrCreate: function() {
    var self = this;
    var map_id = this.table.get('map_id');
    if(!map_id) {
      this.create();
    } else {
      this.set({ id: map_id });
      this.fetch({
        error: function() {
          cdb.log.info("creating map for table");
          self.create();
        }
      });
    }
  },

  /**
   * the first version of cartodb contains one single layer
   * per table with information.
   */
  addDataLayer: function(lyr) {
    this.addLayer(lyr);
    this.set({ dataLayer: lyr });
  },

  /**
   * create a new map. this is a helper to use from javascript command line
   */
  create: function() {
    this.unset('id');
    this.set({ table_id: this.table.id });
    this.save();
  },

  /**
   * enable save map each time the viewport changes
   * not working
   */
  autoSave: function() {
    this.bind('change:center', this.delayedSave);
    this.bind('change:zoom', this.delayedSave);
  },

  toJSON: function() {
    var c = _.clone(this.attributes);
    // data layer is a helper to work in local
    delete c.dataLayer;
    return c;
  }

});
<|endoftext|>


<commit_before>/******************************************************************************
 *                                  ~cassie~                                  *
 *                                ‾‾‾‾‾‾‾‾‾‾‾‾                                *
 * Simple future library for JS. Ready to be violently raped by Ajax!         *
 *     _________________________________________________________________      *
 *        Copyright (c) 2011 Quildreen Motta // Licenced under MIT/X11        *
 ******************************************************************************/

//// Module Cassie /////////////////////////////////////////////////////////////
//
// Cassie (short for lil' Cassandra) is a deliciously short future
// library for JavaScript. It provides a simple Promise object that can
// be used as the return value of any asynchronous call.
//
// The idea behind promises is that you can manipulate the return value
// of an asynchronous function before the function has been
// resolved. This allows you to write in a clear chaining DSL rather
// than using a clusterfuck of callbacks.
//
// Take an Ajax request, for example. The usual way::
//
//     var req = ajax.get('data.json'
//               , function (resp) { /* success */
//                   req.update('#data', JSON.parse(resp.responseText))
//               }
//               , function (resp) { /* fail */
//                   req.show_error()
//               })
//     setTimeout(req.fail, 10000)
//
// With promises, you could get this::
//
//     var req = ajax.get('data.json')
//                   .ok().update('#data')
//                   .failed().show_error()
//                   .timeout(10)
//
// You can pass this ``req`` object around, and other functions can add
// their own manipulations to the object as well::
//
//     function log_it(req) {
//         return req.ok(log('success'))
//                   .failed(log('failed'))
//                   .clear_timer() /* disables the timeout */
//     }
//     var req = log_it(ajax.get('data.json').timeout(10))
//

'@cassie',
function (root) {
    if (typeof exports == 'undefined') {
        old    = root.cassie
        cassie = root.cassie = root.cassie || {}
        cassie.clean = function() {
            root.cassie = old
            return cassie
        }}
    else
        cassie = exports

    var cassie, old
      , slice = Array.prototype.slice

      // Constants with values for errors
      , forgotten = {}
      , timeouted = {}

      // Error objects
      , EFulfilled   = new Error('Promise already fulfilled.')
      , EUnfulfilled = new Error('Promise not fulfilled.')

    ///// Object Promise ///////////////////////////////////////////////////////
    //
    // Creates a deferred object, that can be manipulated before the
    // value is actually resolved. As soon as it is fulfilled, this
    // promise will apply the pending actions.
    //
    // You can either return the promise directly, or take full
    // advantage of it by inheriting the ``Promise``'s prototoype and
    // adding your own custom methods.
    //
    function Promise () {
        this.callbacks   = {}
        this.flush_queue = []
        this.value       = null
        this.timer       = null
        this.defaultev   = 'done'
    }
    Promise.prototype = function() {
        return { add:         add
               , flush:       flush
               , done:        done
               , bind:        bind
               , fail:        fail
               , timeout:     timeout
               , clear_timer: clear_timer
               , forget:      forget

               // Shortcuts for add(event[, callback])
               , ok:          ok
               , failed:      failed
               , timeouted:   _timeouted
               , forgotten:   _forgotten }

        ////// Function add_callback ///////////////////////////////////////////
        // ::
        //     add_callback(Obj promise, Str event, Fn callback) → Fn
        //
        // Adds a callback to a ``Promise``.
        //
        // The callback will be called whenever the given event happens
        // within the given promise, in the context of the promise (ie.:
        // ``this`` inside the callback will refer to the given promise)
        // and the arguments provided when the promise was fulfilled.
        //
        // Returns the given callback function.
        //
        function add_callback(promise, event, callback) {
            if (!promise.callbacks[event])
                promise.callbacks[event] = []

            promise.callbacks[event].push(callback)
            return callback
        }

        ////// Method add //////////////////////////////////////////////////////
        // ::
        //     add(Str event[, Fn callback]) → Promise
        //
        // Adds a callback to the ``Promise``.
        //
        // Passing a callback directly to the add method is optional, to
        // leverage more specialized promises, Cassie supports defining
        // a default event to which callbacks are bound.
        //
        // For example, instead of writting the following::
        //
        //     promise.add('ok', foo).add('ok', bar)
        //
        // You could go with::
        //
        //     promise.add('ok').foo().bar()
        //
        // Of course, given you have a specialized promise implementing
        // `foo` and `bar`.
        //
        // The default event persists until another `add` call with an
        // explicit event is issued.
        //
        // See :fn:`add_callback` for more information.
        //
        function add(event, callback) {
            if (arguments.length > 1)
                this.defaultev = event
            else {
                callback = event
                event    = this.defaultev }

            if (this.value && callback) callback.apply(this, this.value)
            else                        add_callback(this, event, callback)

            return this
        }

        ////// Method flush ////////////////////////////////////////////////////
        // ::
        //     flush(Str event) → Promise
        //
        // Calls all callbacks associated with the given event.
        //
        // The callbacks are called in the context of this ``Promise``
        // (ie.: ``this`` inside such callback will refer to this
        // ``Promise``), and with any arguments that have been passed to
        // the promise when it was fulfilled.
        //
        function flush(event) {
            if (!this.value) this.flush_queue.push(event)
            else while (event = this.flush_queue.shift())
                flush_ev(this, event)

            return this
        }

        function flush_ev(promise, event) {
            var callbacks = promise.callbacks[event] || []
              , current

            while (current = callbacks.shift())
                current.apply(promise, promise.value)
        }

        ////// Method done /////////////////////////////////////////////////////
        // ::
        //     done(ArrayLike values) → Promise
        //
        // Resolves the promise to the given values and call the
        // callbacks defined for ``done``.
        //
        // The given value array is cloned, then assigned to the
        // promise. This makes it easier for caller functions to just
        // pass the ``arguments`` object straight up to this function.
        //
        // If the promise has already been resolved, this method is a
        // noop.
        //
        function done(values) {
            if (!this.value) {
                this.clear_timer().flush('done')
                this.value = slice.call(values)
                this.flush() }
            return this
        }

        ////// Method fail /////////////////////////////////////////////////////
        // ::
        //     fail(Obj error) → Promise
        //
        // Fails to fulfill the promise, and calls all the ``fail``
        // callbacks passing the error as parameter.
        //
        // See :fn:`done` for more information.
        //
        function fail() {
            return this.flush('fail').done(arguments)
        }

        ////// Method bind /////////////////////////////////////////////////////
        // ::
        //     bind(values...) → Promise
        //
        // Successfully fulfills the promise, and calls the ``bind``
        // callbacks passing the values as parameter.
        //
        // See :fn:`resolve` for more information.
        //
        function bind() {
            return this.flush('ok').done(arguments)
        }

        ////// Method timeout //////////////////////////////////////////////////
        // ::
        //     timeout(Num delay) → Promise
        //
        // Fails to fulfill the promise after the given number of
        // seconds.
        //
        // The promise fails with the value of ``timeouted``.
        //
        function timeout(delay) {
            var promise = this
            this.timer = setTimeout(function(){
                promise.flush('timeouted')
                       .fail(timeouted)
            }, delay * 1000)
            return this
        }

        ////// Method clear_timer //////////////////////////////////////////////
        // ::
        //     clear_timer() → Promise
        //
        // Clears any timer that may exist for this promise.
        //
        function clear_timer() {
            clearTimeout(this.timer)
            return this
        }

        ////// Method forget ///////////////////////////////////////////////////
        // ::
        //     forget() → Promise
        //
        // Cancels the promise, and fails with the value of ``forgotten``.
        //
        function forget() {
            return this.flush('forgotten').fail(forgotten)
        }

        ////// -Shortcuts for add(event[, callback]) //////////////////////////
        function ok(fn)         { return this.add('ok',        fn) }
        function failed(fn)     { return this.add('fail',      fn) }
        function _timeouted(fn) { return this.add('timeouted', fn) }
        function _forgotten(fn) { return this.add('forgotten', fn) }
    }()

    ///// Exṕorts //////////////////////////////////////////////////////////////
    cassie.Promise      = Promise
    cassie.forgotten    = forgotten
    cassie.timeouted    = timeouted
    cassie.EFulfilled   = EFulfilled
    cassie.EUnfulfilled = EUnfulfilled
}(this)<commit_msg>Fixes adding callbacks to a queue.<commit_after>/******************************************************************************
 *                                  ~cassie~                                  *
 *                                ‾‾‾‾‾‾‾‾‾‾‾‾                                *
 * Simple future library for JS. Ready to be violently raped by Ajax!         *
 *     _________________________________________________________________      *
 *        Copyright (c) 2011 Quildreen Motta // Licenced under MIT/X11        *
 ******************************************************************************/

//// Module Cassie /////////////////////////////////////////////////////////////
//
// Cassie (short for lil' Cassandra) is a deliciously short future
// library for JavaScript. It provides a simple Promise object that can
// be used as the return value of any asynchronous call.
//
// The idea behind promises is that you can manipulate the return value
// of an asynchronous function before the function has been
// resolved. This allows you to write in a clear chaining DSL rather
// than using a clusterfuck of callbacks.
//
// Take an Ajax request, for example. The usual way::
//
//     var req = ajax.get('data.json'
//               , function (resp) { /* success */
//                   req.update('#data', JSON.parse(resp.responseText))
//               }
//               , function (resp) { /* fail */
//                   req.show_error()
//               })
//     setTimeout(req.fail, 10000)
//
// With promises, you could get this::
//
//     var req = ajax.get('data.json')
//                   .ok().update('#data')
//                   .failed().show_error()
//                   .timeout(10)
//
// You can pass this ``req`` object around, and other functions can add
// their own manipulations to the object as well::
//
//     function log_it(req) {
//         return req.ok(log('success'))
//                   .failed(log('failed'))
//                   .clear_timer() /* disables the timeout */
//     }
//     var req = log_it(ajax.get('data.json').timeout(10))
//

'@cassie',
function (root) {
    if (typeof exports == 'undefined') {
        old    = root.cassie
        cassie = root.cassie = root.cassie || {}
        cassie.clean = function() {
            root.cassie = old
            return cassie
        }}
    else
        cassie = exports

    var cassie, old
      , slice = Array.prototype.slice

      // Constants with values for errors
      , forgotten = {}
      , timeouted = {}

      // Error objects
      , EFulfilled   = new Error('Promise already fulfilled.')
      , EUnfulfilled = new Error('Promise not fulfilled.')

    ///// Object Promise ///////////////////////////////////////////////////////
    //
    // Creates a deferred object, that can be manipulated before the
    // value is actually resolved. As soon as it is fulfilled, this
    // promise will apply the pending actions.
    //
    // You can either return the promise directly, or take full
    // advantage of it by inheriting the ``Promise``'s prototoype and
    // adding your own custom methods.
    //
    function Promise () {
        this.callbacks   = {}
        this.flush_queue = []
        this.value       = null
        this.timer       = null
        this.defaultev   = 'done'
    }
    Promise.prototype = function() {
        return { add:         add
               , flush:       flush
               , done:        done
               , bind:        bind
               , fail:        fail
               , timeout:     timeout
               , clear_timer: clear_timer
               , forget:      forget

               // Shortcuts for add(event[, callback])
               , ok:          ok
               , failed:      failed
               , timeouted:   _timeouted
               , forgotten:   _forgotten }

        ////// Function add_callback ///////////////////////////////////////////
        // ::
        //     add_callback(Obj promise, Str event, Fn callback) → Fn
        //
        // Adds a callback to a ``Promise``.
        //
        // The callback will be called whenever the given event happens
        // within the given promise, in the context of the promise (ie.:
        // ``this`` inside the callback will refer to the given promise)
        // and the arguments provided when the promise was fulfilled.
        //
        // Returns the given callback function.
        //
        function add_callback(promise, event, callback) {
            get_queue(promise, event).push(callback)
            return callback
        }

        function get_queue(promise, event) {
            return promise.callbacks[event]
                || (promise.callbacks[event] = [])
        }

        ////// Method add //////////////////////////////////////////////////////
        // ::
        //     add(Str event[, Fn callback]) → Promise
        //
        // Adds a callback to the ``Promise``.
        //
        // Passing a callback directly to the add method is optional, to
        // leverage more specialized promises, Cassie supports defining
        // a default event to which callbacks are bound.
        //
        // For example, instead of writting the following::
        //
        //     promise.add('ok', foo).add('ok', bar)
        //
        // You could go with::
        //
        //     promise.add('ok').foo().bar()
        //
        // Of course, given you have a specialized promise implementing
        // `foo` and `bar`.
        //
        // The default event persists until another `add` call with an
        // explicit event is issued.
        //
        // See :fn:`add_callback` for more information.
        //
        function add(event, callback) {
            if (typeof event == 'function') {
                callback = event
                event    = this.defaultev }

            _add(this, event, callback)
            return this
        }

        function _add(promise, event, callback) {
            promise.defaultev = event
            if (promise.value)
                fire(promise, event, callback)
            else
                add_callback(promise, event, callback)
        }

        function fire(promise, event, callback) {
            var queue = get_queue(promise, event)
            if (callback && queue.flushed)
                return callback.apply(promise, promise.value)
        }

        ////// Method flush ////////////////////////////////////////////////////
        // ::
        //     flush(Str event) → Promise
        //
        // Calls all callbacks associated with the given event.
        //
        // The callbacks are called in the context of this ``Promise``
        // (ie.: ``this`` inside such callback will refer to this
        // ``Promise``), and with any arguments that have been passed to
        // the promise when it was fulfilled.
        //
        function flush(event) {
            if (!this.value)
                this.flush_queue.push(event)
            else while (event = this.flush_queue.shift())
                flush_ev(this, event)

            return this
        }

        function flush_ev(promise, event) {
            var callbacks = promise.callbacks[event] || []
              , current

            while (current = callbacks.shift())
                current.apply(promise, promise.value)

            callbacks.flushed = true
        }

        ////// Method done /////////////////////////////////////////////////////
        // ::
        //     done(ArrayLike values) → Promise
        //
        // Resolves the promise to the given values and call the
        // callbacks defined for ``done``.
        //
        // The given value array is cloned, then assigned to the
        // promise. This makes it easier for caller functions to just
        // pass the ``arguments`` object straight up to this function.
        //
        // If the promise has already been resolved, this method is a
        // noop.
        //
        function done(values) {
            if (!this.value) {
                this.clear_timer().flush('done')
                this.value = slice.call(values)
                this.flush() }
            return this
        }

        ////// Method fail /////////////////////////////////////////////////////
        // ::
        //     fail(Obj error) → Promise
        //
        // Fails to fulfill the promise, and calls all the ``fail``
        // callbacks passing the error as parameter.
        //
        // See :fn:`done` for more information.
        //
        function fail() {
            return this.flush('fail').done(arguments)
        }

        ////// Method bind /////////////////////////////////////////////////////
        // ::
        //     bind(values...) → Promise
        //
        // Successfully fulfills the promise, and calls the ``bind``
        // callbacks passing the values as parameter.
        //
        // See :fn:`resolve` for more information.
        //
        function bind() {
            return this.flush('ok').done(arguments)
        }

        ////// Method timeout //////////////////////////////////////////////////
        // ::
        //     timeout(Num delay) → Promise
        //
        // Fails to fulfill the promise after the given number of
        // seconds.
        //
        // The promise fails with the value of ``timeouted``.
        //
        function timeout(delay) {
            var promise = this
            this.timer = setTimeout(function(){
                promise.flush('timeouted')
                       .fail(timeouted)
            }, delay * 1000)
            return this
        }

        ////// Method clear_timer //////////////////////////////////////////////
        // ::
        //     clear_timer() → Promise
        //
        // Clears any timer that may exist for this promise.
        //
        function clear_timer() {
            clearTimeout(this.timer)
            return this
        }

        ////// Method forget ///////////////////////////////////////////////////
        // ::
        //     forget() → Promise
        //
        // Cancels the promise, and fails with the value of ``forgotten``.
        //
        function forget() {
            return this.flush('forgotten').fail(forgotten)
        }

        ////// -Shortcuts for add(event[, callback]) //////////////////////////
        function ok(fn)         { return this.add('ok',        fn) }
        function failed(fn)     { return this.add('fail',      fn) }
        function _timeouted(fn) { return this.add('timeouted', fn) }
        function _forgotten(fn) { return this.add('forgotten', fn) }
    }()

    ///// Exṕorts //////////////////////////////////////////////////////////////
    cassie.Promise      = Promise
    cassie.forgotten    = forgotten
    cassie.timeouted    = timeouted
    cassie.EFulfilled   = EFulfilled
    cassie.EUnfulfilled = EUnfulfilled
}(this)<|endoftext|>


<commit_before>/**
 * @copyright Copyright 2014 Google Inc. All rights reserved.
 *
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file or at
 * https://developers.google.com/open-source/licenses/bsd
 *
 * @fileoverview Utility methods for updating and verifying dashboards.
 *
 * @author joemu@google.com (Joe Allan Muharsky)
 */

goog.provide('p3rf.perfkit.explorer.components.dashboard.versions.DashboardVersionUtil');

goog.scope(function() {
  /**
   * @constructor
   */
  p3rf.perfkit.explorer.components.dashboard.versions.DashboardVersionUtil = function() {};
  var DashboardVersionUtil = p3rf.perfkit.explorer.components.dashboard.versions.DashboardVersionUtil;

  /**
   * Updates the containers and widgets of a dashboard, based on supplied functions.
   *
   * @param dashboard The DashboardModel object to update.
   * @param {?function(container)} updateContainerFn The function to apply to each container.
   * @param {?function(widget)} updateWidgetFn The function to apply to each widget.
   */
  DashboardVersionUtil.UpdateDashboard = function(dashboard, updateContainerFn, updateWidgetFn) {
    angular.forEach(dashboard.children, function(containerConfig) {
      updateContainerFn && !updateContainerFn(containerConfig.container);

      if (updateWidgetFn) {
        angular.forEach(containerConfig.container.children, function(widget) {
          updateWidgetFn(widget);
        });
      }
    });
  };

  /**
   * Verifies the containers and widgets of a dashboard, based on supplied functions.  If any of
   * the provided verify* functions fails to return 'true', the function will return false and
   * halt the verification of widgets/containers.
   *
   * @param dashboard The DashboardModel object to update.
   * @param {?function(container)} verifyContainerFn The function to apply to each container.
   * @param {?function(widget)} verifyWidgetFn The function to apply to each widget.
   */
  DashboardVersionUtil.VerifyDashboard = function(dashboard, verifyContainerFn, verifyWidgetFn) {
    var container, widget = null;

    for (var i = 0, containerCount = dashboard.children.length; i < containerCount; ++i) {
      container = dashboard.children[i].container;

      if (verifyContainerFn && !verifyContainerFn(container)) {
        return false;
      }

      if (verifyWidgetFn) {
        for (var j = 0, widgetCount = container.children.length; j < widgetCount; ++j) {
          widget = container.children[i];

          if (!verifyWidgetFn(widget)) {
            return false;
          }
        }
      }
    }

    return true;
  };
});
<commit_msg>=Fix indexer.<commit_after>/**
 * @copyright Copyright 2014 Google Inc. All rights reserved.
 *
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file or at
 * https://developers.google.com/open-source/licenses/bsd
 *
 * @fileoverview Utility methods for updating and verifying dashboards.
 *
 * @author joemu@google.com (Joe Allan Muharsky)
 */

goog.provide('p3rf.perfkit.explorer.components.dashboard.versions.DashboardVersionUtil');

goog.scope(function() {
  /**
   * @constructor
   */
  p3rf.perfkit.explorer.components.dashboard.versions.DashboardVersionUtil = function() {};
  var DashboardVersionUtil = p3rf.perfkit.explorer.components.dashboard.versions.DashboardVersionUtil;

  /**
   * Updates the containers and widgets of a dashboard, based on supplied functions.
   *
   * @param dashboard The DashboardModel object to update.
   * @param {?function(container)} updateContainerFn The function to apply to each container.
   * @param {?function(widget)} updateWidgetFn The function to apply to each widget.
   */
  DashboardVersionUtil.UpdateDashboard = function(dashboard, updateContainerFn, updateWidgetFn) {
    angular.forEach(dashboard.children, function(containerConfig) {
      updateContainerFn && !updateContainerFn(containerConfig.container);

      if (updateWidgetFn) {
        angular.forEach(containerConfig.container.children, function(widget) {
          updateWidgetFn(widget);
        });
      }
    });
  };

  /**
   * Verifies the containers and widgets of a dashboard, based on supplied functions.  If any of
   * the provided verify* functions fails to return 'true', the function will return false and
   * halt the verification of widgets/containers.
   *
   * @param dashboard The DashboardModel object to update.
   * @param {?function(container)} verifyContainerFn The function to apply to each container.
   * @param {?function(widget)} verifyWidgetFn The function to apply to each widget.
   */
  DashboardVersionUtil.VerifyDashboard = function(dashboard, verifyContainerFn, verifyWidgetFn) {
    var container, widget = null;

    for (var i = 0, containerCount = dashboard.children.length; i < containerCount; ++i) {
      container = dashboard.children[i].container;

      if (verifyContainerFn && !verifyContainerFn(container)) {
        return false;
      }

      if (verifyWidgetFn) {
        for (var j = 0, widgetCount = container.children.length; j < widgetCount; ++j) {
          widget = container.children[j];

          if (!verifyWidgetFn(widget)) {
            return false;
          }
        }
      }
    }

    return true;
  };
});
<|endoftext|>


<commit_before>(function() {

  'use strict';

  var ENTER_KEY = 13;
  var newTodoDom = document.getElementById('new-todo');
  var syncDom = document.getElementById('sync-wrapper');

  // EDITING STARTS HERE (you dont need to edit anything above this line)

  var db = new Pouch('todos');
  var remoteCouch = false;

  db.info(function(err, info) {
    db.changes({since: info.update_seq, onChange: showTodos, continuous: true});
  });

  // We have to create a new todo document and enter it in the database
  function addTodo(text) {
    var todo = {
      title: text,
      completed: false
    };
    db.post(todo, function(err, result) {
      if (!err) {
        console.log('Successfully posted a todo!');
      }
    });
  }

  // Show the current list of todos by reading them from the database
  function showTodos() {
    db.allDocs({include_docs: true}, function(err, doc) {
      redrawTodosUI(doc.rows);
    });
  }

  function checkboxChanged(todo, event) {
    todo.completed = event.target.checked;
    db.put(todo);
  }

  // User pressed the delete button for a todo, delete it
  function deleteButtonPressed(todo) {
  }

  // The input box when editing a todo has blurred, we should save
  // the new title or delete the todo if the title is empty
  function todoBlurred(todo, event) {
  }

  // Initialise a sync with the remote server
  function sync() {
  }

  // EDITING STARTS HERE (you dont need to edit anything below this line)

  // There was some form or error syncing
  function syncError() {
    syncDom.setAttribute('data-sync-state', 'error');
  }

  // User has double clicked a todo, display an input so they can edit the title
  function todoDblClicked(todo) {
    var div = document.getElementById('li_' + todo._id);
    var inputEditTodo = document.getElementById('input_' + todo._id);
    div.className = 'editing';
    inputEditTodo.focus();
  }

  // If they press enter while editing an entry, blur it to trigger save
  // (or delete)
  function todoKeyPressed(todo, event) {
    if (event.keyCode === ENTER_KEY) {
      var inputEditTodo = document.getElementById('input_' + todo._id);
      inputEditTodo.blur();
    }
  }

  // Given an object representing a todo, this will create a list item
  // to display it.
  function createTodoListItem(todo) {
    var checkbox = document.createElement('input');
    checkbox.className = 'toggle';
    checkbox.type = 'checkbox';
    checkbox.addEventListener('change', checkboxChanged.bind(this, todo));

    var label = document.createElement('label');
    label.appendChild( document.createTextNode(todo.title));
    label.addEventListener('dblclick', todoDblClicked.bind(this, todo));

    var deleteLink = document.createElement('button');
    deleteLink.className = 'destroy';
    deleteLink.addEventListener( 'click', deleteButtonPressed.bind(this, todo));

    var divDisplay = document.createElement('div');
    divDisplay.className = 'view';
    divDisplay.appendChild(checkbox);
    divDisplay.appendChild(label);
    divDisplay.appendChild(deleteLink);

    var inputEditTodo = document.createElement('input');
    inputEditTodo.id = 'input_' + todo._id;
    inputEditTodo.className = 'edit';
    inputEditTodo.value = todo.title;
    inputEditTodo.addEventListener('keypress', todoKeyPressed.bind(this, todo));
    inputEditTodo.addEventListener('blur', todoBlurred.bind(this, todo));

    var li = document.createElement('li');
    li.id = 'li_' + todo._id;
    li.appendChild(divDisplay);
    li.appendChild(inputEditTodo);

    if (todo.completed) {
      li.className += 'complete';
      checkbox.checked = true;
    }

    return li;
  }

  function redrawTodosUI(todos) {
    var ul = document.getElementById('todo-list');
    ul.innerHTML = '';
    todos.forEach(function(todo) {
      ul.appendChild(createTodoListItem(todo.doc));
    });
  }

  function newTodoKeyPressHandler( event ) {
    if (event.keyCode === ENTER_KEY) {
      addTodo(newTodoDom.value);
      newTodoDom.value = '';
    }
  }

  function addEventListeners() {
    newTodoDom.addEventListener('keypress', newTodoKeyPressHandler, false);
  }

  addEventListeners();
  showTodos();

  if (remoteCouch) {
    sync();
  }

})();
<commit_msg>Step 7: Delete a todo from PouchDB<commit_after>(function() {

  'use strict';

  var ENTER_KEY = 13;
  var newTodoDom = document.getElementById('new-todo');
  var syncDom = document.getElementById('sync-wrapper');

  // EDITING STARTS HERE (you dont need to edit anything above this line)

  var db = new Pouch('todos');
  var remoteCouch = false;

  db.info(function(err, info) {
    db.changes({since: info.update_seq, onChange: showTodos, continuous: true});
  });

  // We have to create a new todo document and enter it in the database
  function addTodo(text) {
    var todo = {
      title: text,
      completed: false
    };
    db.post(todo, function(err, result) {
      if (!err) {
        console.log('Successfully posted a todo!');
      }
    });
  }

  // Show the current list of todos by reading them from the database
  function showTodos() {
    db.allDocs({include_docs: true}, function(err, doc) {
      redrawTodosUI(doc.rows);
    });
  }

  function checkboxChanged(todo, event) {
    todo.completed = event.target.checked;
    db.put(todo);
  }

  // User pressed the delete button for a todo, delete it
  function deleteButtonPressed(todo) {
    db.remove(todo);
  }

  // The input box when editing a todo has blurred, we should save
  // the new title or delete the todo if the title is empty
  function todoBlurred(todo, event) {
  }

  // Initialise a sync with the remote server
  function sync() {
  }

  // EDITING STARTS HERE (you dont need to edit anything below this line)

  // There was some form or error syncing
  function syncError() {
    syncDom.setAttribute('data-sync-state', 'error');
  }

  // User has double clicked a todo, display an input so they can edit the title
  function todoDblClicked(todo) {
    var div = document.getElementById('li_' + todo._id);
    var inputEditTodo = document.getElementById('input_' + todo._id);
    div.className = 'editing';
    inputEditTodo.focus();
  }

  // If they press enter while editing an entry, blur it to trigger save
  // (or delete)
  function todoKeyPressed(todo, event) {
    if (event.keyCode === ENTER_KEY) {
      var inputEditTodo = document.getElementById('input_' + todo._id);
      inputEditTodo.blur();
    }
  }

  // Given an object representing a todo, this will create a list item
  // to display it.
  function createTodoListItem(todo) {
    var checkbox = document.createElement('input');
    checkbox.className = 'toggle';
    checkbox.type = 'checkbox';
    checkbox.addEventListener('change', checkboxChanged.bind(this, todo));

    var label = document.createElement('label');
    label.appendChild( document.createTextNode(todo.title));
    label.addEventListener('dblclick', todoDblClicked.bind(this, todo));

    var deleteLink = document.createElement('button');
    deleteLink.className = 'destroy';
    deleteLink.addEventListener( 'click', deleteButtonPressed.bind(this, todo));

    var divDisplay = document.createElement('div');
    divDisplay.className = 'view';
    divDisplay.appendChild(checkbox);
    divDisplay.appendChild(label);
    divDisplay.appendChild(deleteLink);

    var inputEditTodo = document.createElement('input');
    inputEditTodo.id = 'input_' + todo._id;
    inputEditTodo.className = 'edit';
    inputEditTodo.value = todo.title;
    inputEditTodo.addEventListener('keypress', todoKeyPressed.bind(this, todo));
    inputEditTodo.addEventListener('blur', todoBlurred.bind(this, todo));

    var li = document.createElement('li');
    li.id = 'li_' + todo._id;
    li.appendChild(divDisplay);
    li.appendChild(inputEditTodo);

    if (todo.completed) {
      li.className += 'complete';
      checkbox.checked = true;
    }

    return li;
  }

  function redrawTodosUI(todos) {
    var ul = document.getElementById('todo-list');
    ul.innerHTML = '';
    todos.forEach(function(todo) {
      ul.appendChild(createTodoListItem(todo.doc));
    });
  }

  function newTodoKeyPressHandler( event ) {
    if (event.keyCode === ENTER_KEY) {
      addTodo(newTodoDom.value);
      newTodoDom.value = '';
    }
  }

  function addEventListeners() {
    newTodoDom.addEventListener('keypress', newTodoKeyPressHandler, false);
  }

  addEventListeners();
  showTodos();

  if (remoteCouch) {
    sync();
  }

})();
<|endoftext|>


<commit_before>
//TODO uncomment and write more tests
/* Tests for fileBrowser.js for My Projects in Dashboard */
/*global describe, it, expect, example, before, after, beforeEach, afterEach, mocha, sinon*/
'use strict';
var assert = require('chai').assert;

var $ = require('jquery');
var $osf = require('js/osfHelpers');
var fb = require('js/dashboard.js');
var m = require('mithril');

var FileBrowser = fb.Dashboard;
var LinkObject = fb.LinkObject;

describe('fileBrowser', function() {
    describe('LinkObject', function () {
        var collection;
        var tag;
        var name;
        var node;

        before(function () {
            collection = new LinkObject('collection', {
                path: 'users/me/nodes/',
                query: {'related_counts': true},
                systemCollection: true
            }, 'All My Projects');
            tag = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else');
            name = new LinkObject('name', { id : '8q36f', query : { 'related_counts' : true }}, 'Caner Uguz');
            node = new LinkObject('node', { uid : 'qwerty'}, 'Node Title');
        });

        describe('#attributes', function () {
            it('should return an id of 1', function () {
                assert.equal(collection.id, 1);
            });
            it('should throw error when no arguments passed', function () {
                assert.throws(function(){ var missing = new LinkObject(); }, Error);
            });
            it('should throw error when index is not number and  > 0', function () {
                assert.throws(function(){ var missing = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else', 'index'); }, Error);
                assert.throws(function(){ var missing = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else', -1); }, Error);
            });
        });

        describe('#generateLinks', function () {
            it('should return correct collection link', function () {
                assert.equal(collection.link, 'users/me/nodes/?related_counts=true');
            });
            it('should return correct tag link', function () {
                assert.equal(tag.link, 'nodes/?filter%5Btags%5D=something&related_counts=true&embed=contributors');
            });
            it('should return correct name link', function () {
                assert.equal(name.link, 'users/8q36f/nodes/?related_counts=true&embed=contributors');
            });
            it('should return correct node link', function () {
                assert.equal(node.link, 'nodes/qwerty/children/?related_counts=true&embed=contributors');
            });
        });
    });
});<commit_msg>Fix broken tests<commit_after>
//TODO uncomment and write more tests
/* Tests for fileBrowser.js for My Projects in Dashboard */
/*global describe, it, expect, example, before, after, beforeEach, afterEach, mocha, sinon*/
'use strict';
var assert = require('chai').assert;

var $ = require('jquery');
var $osf = require('js/osfHelpers');
var fb = require('js/dashboard.js');
var m = require('mithril');

var FileBrowser = fb.Dashboard;
var LinkObject = fb.LinkObject;

describe('fileBrowser', function() {
    describe('LinkObject', function () {
        var collection;
        var tag;
        var name;
        var node;

        before(function () {
            collection = new LinkObject('collection', {
                path: 'users/me/nodes/',
                query: {'related_counts': true},
                systemCollection: true
            }, 'All My Projects');
            tag = new LinkObject('tag', { tag : 'something', query : { 'related_counts' : true }}, 'Something Else');
            name = new LinkObject('name', { id : '8q36f', query : { 'related_counts' : true }}, 'Caner Uguz');
            node = new LinkObject('node', { id : 'qwerty'}, 'Node Title');
        });

        describe('#attributes', function () {
            it('should return an id of 1', function () {
                assert.equal(collection.id, 1);
            });
            it('should throw error when no arguments passed', function () {
                assert.throws(function(){ var missing = new LinkObject(); }, Error);
            });
        });

        describe('#generateLinks', function () {
            it('should return correct collection link', function () {
                assert.equal(collection.link, 'users/me/nodes/?related_counts=true');
            });
            it('should return correct tag link', function () {
                assert.equal(tag.link, 'nodes/?filter%5Btags%5D=something&related_counts=true&embed=contributors');
            });
            it('should return correct name link', function () {
                assert.equal(name.link, 'users/8q36f/nodes/?related_counts=true&embed=contributors');
            });
            it('should return correct node link', function () {
                assert.equal(node.link, 'nodes/qwerty/children/?related_counts=true&page%5Bsize%5D=60&embed=contributors');
            });
        });
    });
});<|endoftext|>


<commit_before>var Dependency = require('./dependency').Dependency;
var fs = require('fs');
var colors = require('colors');

function extractModuleName(s) {
	var slash = s.lastIndexOf('/');
	var dot = s.lastIndexOf('.');

	// pattern matching!
	if (slash === -1) {
		if (dot === -1) {
			return s;
		} else {
			return s.substr(0, dot);
		}
	} else {
		if (dot === -1) {
			return s.substr(slash + 1);
		} else {
			return s.substring(slash + 1, dot);
		}
	}
}

/**
 * Replaces full paths with module names in a graph structure
 * @param {Graph} graph
 * @returns {Graph}
 */
function getNiceGraph(graph) {
	var niceGraph = {};
	for (var key in graph) {
		var niceName = extractModuleName(key);
		niceGraph[niceName] = graph[key].map(extractModuleName);
	}
	return niceGraph;
}

function checkCycles(graph) {
	// check for cycles in the graph
	var traversed;

	// bad, slow alg to check for cycles
	function walk(nodeName, startNode, path) {
		if (nodeName === startNode) {
			console.log('Cycle detected!'.red);
			throw path;
		}
		if (startNode === null) { startNode = nodeName; }

		if (traversed[nodeName]) { return; }

		traversed[nodeName] = true;

		if (graph[nodeName]) {
			graph[nodeName].forEach(function (next) {
				walk(next, startNode, path + ' - ' + next);
			});
		}
	}

	// start walking from every node
	for (var key in graph) {
		if (key !== 'goo') {
			traversed = {};
			walk(key, null, key);
		}
	}

	console.log('No cycles found'.green);
}

// ---
function cycleDetector() {
	// do the whole tree
	Dependency.getTree(rootPath, function (graph) {
		// get the nice graph - without paths
		graph = getNiceGraph(graph);

		// check for cycles
		checkCycles(graph);
	});
}

function dependencies(fileName) {
	Dependency.getDependencies(fileName, function (properFileName, dependencies) {
		console.log(properFileName, 'is dependant on\n', dependencies);
	});
}

function dependants(fileName) {
	Dependency.getDependants(rootPath, fileName, function (properFileName, dependants) {
		console.log(properFileName, 'is required by\n', dependants);
	});
}

function help() {
	var helpString = [].join('\n');

	console.log(helpString);
}

var rootPath;

function main() {
	rootPath = 'src/';
	var args = process.argv;
	if (args.length === 2) {
		cycleDetector();
	} else {
		if (args[2] === '--cycles') {
			cycleDetector();
		} else if (args[2] === '--dependencies') {
			dependencies(args[3]);
		} else if (args[2] === '--dependants') {
			dependants(args[3]);
		} else {
			 help();
		}
	}
}

main();<commit_msg>Dependency analyzer gives warnings for bad parameters<commit_after>var Dependency = require('./dependency').Dependency;
var fs = require('fs');
var colors = require('colors');

function extractModuleName(s) {
	var slash = s.lastIndexOf('/');
	var dot = s.lastIndexOf('.');

	// pattern matching!
	if (slash === -1) {
		if (dot === -1) {
			return s;
		} else {
			return s.substr(0, dot);
		}
	} else {
		if (dot === -1) {
			return s.substr(slash + 1);
		} else {
			return s.substring(slash + 1, dot);
		}
	}
}

/**
 * Replaces full paths with module names in a graph structure
 * @param {Graph} graph
 * @returns {Graph}
 */
function getNiceGraph(graph) {
	var niceGraph = {};
	for (var key in graph) {
		var niceName = extractModuleName(key);
		niceGraph[niceName] = graph[key].map(extractModuleName);
	}
	return niceGraph;
}

function checkCycles(graph) {
	// check for cycles in the graph
	var traversed;

	// bad, slow alg to check for cycles
	function walk(nodeName, startNode, path) {
		if (nodeName === startNode) {
			console.log('Cycle detected!'.red);
			throw path;
		}
		if (startNode === null) { startNode = nodeName; }

		if (traversed[nodeName]) { return; }

		traversed[nodeName] = true;

		if (graph[nodeName]) {
			graph[nodeName].forEach(function (next) {
				walk(next, startNode, path + ' - ' + next);
			});
		}
	}

	// start walking from every node
	for (var key in graph) {
		if (key !== 'goo') {
			traversed = {};
			walk(key, null, key);
		}
	}

	console.log('No cycles found'.green);
}

// ---
function cycleDetector() {
	// do the whole tree
	Dependency.getTree(rootPath, function (graph) {
		// get the nice graph - without paths
		graph = getNiceGraph(graph);

		// check for cycles
		checkCycles(graph);
	});
}

function dependencies(fileName) {
	Dependency.getDependencies(fileName, function (properFileName, dependencies) {
		console.log(properFileName, 'is dependant on\n', dependencies);
	});
}

function dependants(fileName) {
	Dependency.getDependants(rootPath, fileName, function (properFileName, dependants) {
		console.log(properFileName, 'is required by\n', dependants);
	});
}

function help() {
	var helpString = [
		"Usage:",
		" --cycles",
		" --dependencies <modulepath>",
		" --dependants <modulepath>"
	].join('\n');

	console.log(helpString);
}

var rootPath;

function main() {
	rootPath = 'src/';
	var args = process.argv;
	if (args.length === 2) {
		cycleDetector();
	} else {
		if (args[2] === '--cycles' && args.length === 3) {
			cycleDetector();
		} else if (args[2] === '--dependencies' && args.length === 4) {
			dependencies(args[3]);
		} else if (args[2] === '--dependants' && args.length === 4) {
			dependants(args[3]);
		} else {
			 help();
		}
	}
}

main();<|endoftext|>