From 673661b798f809489cc51a79c8bcd34c7afcc5e0 Mon Sep 17 00:00:00 2001 From: Augier <contact@c-henry.fr> Date: Thu, 12 Mar 2015 21:23:40 +0100 Subject: [PATCH] Ported searchbar --- .../javascripts/app/views/header_view.js | 17 ++-- .../app/views/notifications_badge_view.js | 12 +-- .../javascripts/app/views/searchbar_view.js | 70 ++++++++++++++++ app/assets/javascripts/widgets/header.js | 15 ---- app/assets/javascripts/widgets/search.js | 83 ------------------- app/assets/templates/header_tpl.jst.hbs | 2 +- .../javascripts/app/views/search_view_spec.js | 14 ++++ spec/javascripts/widgets/search-spec.js | 12 --- 8 files changed, 100 insertions(+), 125 deletions(-) create mode 100644 app/assets/javascripts/app/views/searchbar_view.js delete mode 100644 app/assets/javascripts/widgets/header.js delete mode 100644 app/assets/javascripts/widgets/search.js create mode 100644 spec/javascripts/app/views/search_view_spec.js delete mode 100644 spec/javascripts/widgets/search-spec.js diff --git a/app/assets/javascripts/app/views/header_view.js b/app/assets/javascripts/app/views/header_view.js index a3c9aceeb6..a3a2197aa4 100644 --- a/app/assets/javascripts/app/views/header_view.js +++ b/app/assets/javascripts/app/views/header_view.js @@ -2,17 +2,17 @@ app.views.Header = app.views.Base.extend({ - templateName : "header", + templateName: "header", - className : "dark-header", + className: "dark-header", - events :{ - "click ul.dropdown li:first-child" : "toggleUserDropdown", + events: { + "click ul.dropdown li:first-child": "toggleUserDropdown", "focusin #q": "toggleSearchActive", "focusout #q": "toggleSearchActive" }, - initialize : function(){ + initialize: function(){ $(document.body).click($.proxy(this.hideUserDropdown, this)); return this; @@ -21,11 +21,12 @@ app.views.Header = app.views.Base.extend({ postRenderTemplate: function(){ new app.views.Notifications({ el: '#notification_dropdown' }); new app.views.NotificationsBadge({ el: '#notification_badge' }); + new app.views.SearchBar({ el: '#search_people_form' }); }, - menuElement : function(){ return this.$("ul.dropdown"); }, + menuElement: function(){ return this.$("ul.dropdown"); }, - toggleUserDropdown : function(evt){ + toggleUserDropdown: function(evt){ if(evt){ evt.preventDefault(); } this.menuElement().toggleClass("active"); @@ -35,7 +36,7 @@ app.views.Header = app.views.Base.extend({ } }, - hideUserDropdown : function(evt){ + hideUserDropdown: function(evt){ if(this.menuElement().hasClass("active") && !$(evt.target).parents("#user_menu").length){ this.menuElement().removeClass("active"); } diff --git a/app/assets/javascripts/app/views/notifications_badge_view.js b/app/assets/javascripts/app/views/notifications_badge_view.js index e16d222c62..2c3bfee4fa 100644 --- a/app/assets/javascripts/app/views/notifications_badge_view.js +++ b/app/assets/javascripts/app/views/notifications_badge_view.js @@ -8,12 +8,12 @@ app.views.NotificationsBadge = app.views.Base.extend({ initialize: function(){ $(document.body).click($.proxy(this.hideNotifDropdown, this)); - this.currentPage = 2; - this.notificationsLoaded = 10; - this.badge = this.$el; - this.dropdown = $('#notification_dropdown'); - this.dropdownNotifications = this.dropdown.find(".notifications"); - this.ajaxLoader = this.dropdown.find(".ajax_loader"); + this.currentPage = 2; + this.notificationsLoaded = 10; + this.badge = this.$el; + this.dropdown = $('#notification_dropdown'); + this.dropdownNotifications = this.dropdown.find(".notifications"); + this.ajaxLoader = this.dropdown.find(".ajax_loader"); }, toggleNotifDropdown: function(evt){ diff --git a/app/assets/javascripts/app/views/searchbar_view.js b/app/assets/javascripts/app/views/searchbar_view.js new file mode 100644 index 0000000000..6c16265bfe --- /dev/null +++ b/app/assets/javascripts/app/views/searchbar_view.js @@ -0,0 +1,70 @@ +// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later +app.views.SearchBar = app.views.Base.extend({ + initialize: function(){ + this.searchForm = this.$el; + this.searchFormAction = this.searchForm.attr('action'); + this.searchInput = this.searchForm.find('input[type="search"]'); + this.searchInputName = this.searchForm.find('input[type="search"]').attr('name'); + this.searchInputHandle = this.searchForm.find('input[type="search"]').attr('handle'); + this.options = { + cacheLength: 15, + delay: 800, + extraParams: {limit: 4}, + formatItem: this.formatItem, + formatResult: this.formatResult, + max: 5, + minChars: 2, + onSelect: this.selectItemCallback, + parse: this.parse, + scroll: false, + context: this + }; + + var self = this; + this.searchInput.autocomplete(self.searchFormAction + '.json', + $.extend(self.options, { element: self.searchInput })); + }, + + formatItem: function(row){ + if(typeof row.search !== 'undefined') { return Diaspora.I18n.t('search_for', row); } + else { + var item = ''; + if (row.avatar) { item += '<img src="' + row.avatar + '" class="avatar"/>'; } + item += row.name; + if (row.handle) { item += '<div class="search_handle">' + row.handle + '</div>'; } + return item; + } + }, + + formatResult: function(row){ return Handlebars.Utils.escapeExpression(row.name); }, + + parse: function(data) { + var results = data.map(function(person){ + person.name = Handlebars.Utils.escapeExpression(person.name); + return {data : person, value : person.name}; + }); + + var self = this.context; + results.push({ + data: { + name: self.searchInput.val(), + url: self.searchFormAction + '?' + self.searchInputName + '=' + self.searchInput.val(), + search: true + }, + value: self.searchInput.val() + }); + + return results; + }, + + selectItemCallback: function(evt, data, formatted){ + if(data.search === true){ + window.location = this.searchFormAction + '?' + this.searchInputName + '=' + data.name; + } + else{ // The actual result + this.options.element.val(formatted); + window.location = data.url ? data.url : '/tags/' + data.name.substring(1); + } + } +}); +// @license-ends diff --git a/app/assets/javascripts/widgets/header.js b/app/assets/javascripts/widgets/header.js deleted file mode 100644 index e74fb175ac..0000000000 --- a/app/assets/javascripts/widgets/header.js +++ /dev/null @@ -1,15 +0,0 @@ -// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later - -(function() { - var Header = function() { - var self = this; - - this.subscribe("widget/ready", function(evt, header) { - self.search = self.instantiate("Search", header.find(".search_form")); - }); - }; - - Diaspora.Widgets.Header = Header; -})(); -// @license-end - diff --git a/app/assets/javascripts/widgets/search.js b/app/assets/javascripts/widgets/search.js deleted file mode 100644 index 5540751940..0000000000 --- a/app/assets/javascripts/widgets/search.js +++ /dev/null @@ -1,83 +0,0 @@ -// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later - -(function() { - var Search = function() { - var self = this; - - this.subscribe("widget/ready", function(evt, searchForm) { - $.extend(self, { - searchForm: searchForm, - searchFormAction: searchForm.attr("action"), - searchInput: searchForm.find("input[type='search']"), - searchInputName: searchForm.find("input[type='search']").attr("name"), - searchInputHandle: searchForm.find("input[type='search']").attr("handle"), - options: { - cacheLength : 15, - delay : 800, - extraParams : {limit : 4}, - formatItem : self.formatItem, - formatResult : self.formatResult, - max : 5, - minChars : 2, - onSelect: self.selectItemCallback, - parse : self.parse, - scroll : false - } - }); - - self.searchInput.autocomplete(self.searchFormAction + ".json", $.extend(self.options, { - element: self.searchInput - })); - }); - - this.formatItem = function(row) { - if (typeof row.search !== "undefined") { - return Diaspora.I18n.t("search_for", row); - } else { - var item = ""; - if (row.avatar) { - item += "<img src='"+ row.avatar +"' class='avatar'/>"; - } - item += row.name; - if (row.handle) { - item += "<div class='search_handle'>" + row.handle + "</div>"; - } - return item; - } - }; - - this.formatResult = function(row) { - return Handlebars.Utils.escapeExpression(row.name); - }; - - this.parse = function(data) { - var results = data.map(function(person){ - person['name'] = Handlebars.Utils.escapeExpression(person['name']); - return {data : person, value : person['name']}; - }); - - results.push({ - data: { - name: self.searchInput.val(), - url: self.searchFormAction + "?" + self.searchInputName + "=" + self.searchInput.val(), - search: true - }, - value: self.searchInput.val() - }); - - return results; - }; - - this.selectItemCallback = function(evt, data, formatted) { - if (data['search'] === true) { // The placeholder "search for" result - window.location = self.searchFormAction + '?' + self.searchInputName + '=' + data['name']; - } else { // The actual result - self.options.element.val(formatted); - window.location = data['url'] ? data['url'] : "/tags/" + data['name'].substring(1); // we don't want the #-character - } - }; - }; - - Diaspora.Widgets.Search = Search; -})(); -// @license-end diff --git a/app/assets/templates/header_tpl.jst.hbs b/app/assets/templates/header_tpl.jst.hbs index 4fa05b10d7..89f81b5637 100644 --- a/app/assets/templates/header_tpl.jst.hbs +++ b/app/assets/templates/header_tpl.jst.hbs @@ -87,7 +87,7 @@ <div id="global_search"> - <form accept-charset="UTF-8" action="/search" class="search_form" method="get"> + <form id="search_people_form" accept-charset="UTF-8" action="/search" class="search_form" method="get"> <input name="utf8" type="hidden" value="✓"> <input id="q" name="q" placeholder="{{t "header.search"}}" results="5" type="search" autocomplete="off" class="ac_input"> </form> diff --git a/spec/javascripts/app/views/search_view_spec.js b/spec/javascripts/app/views/search_view_spec.js new file mode 100644 index 0000000000..2a1e4fa623 --- /dev/null +++ b/spec/javascripts/app/views/search_view_spec.js @@ -0,0 +1,14 @@ +describe("app.views.SearchBar", function() { + beforeEach(function(){ + this.view = new app.views.SearchBar({ el: '#search_people_form' }); + }); + describe("parse", function() { + it("escapes a persons name", function() { + $("#jasmine_content").html('<form action="#" id="searchForm"></form>'); + + var person = { 'name': '</script><script>alert("xss");</script' }; + var result = this.view.search.parse([$.extend({}, person)]); + expect(result[0].data.name).not.toEqual(person.name); + }); + }); +}); diff --git a/spec/javascripts/widgets/search-spec.js b/spec/javascripts/widgets/search-spec.js deleted file mode 100644 index 4f1fb659a5..0000000000 --- a/spec/javascripts/widgets/search-spec.js +++ /dev/null @@ -1,12 +0,0 @@ -describe("Diaspora.Widgets.Search", function() { - describe("parse", function() { - it("escapes a persons name", function() { - $("#jasmine_content").html('<form action="#" id="searchForm"></form>'); - - var search = Diaspora.BaseWidget.instantiate("Search", $("#jasmine_content > #searchForm")); - var person = {"name": "</script><script>alert('xss');</script"}; - var result = search.parse([$.extend({}, person)]); - expect(result[0].data.name).not.toEqual(person.name); - }); - }); -}); -- GitLab