Skip to content
Snippets Groups Projects
Commit b1bd3f12 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets
Browse files

fix tests. added jquery.timeago.js

parent 124a5e27
No related branches found
No related tags found
No related merge requests found
Showing
with 247 additions and 82 deletions
/**
* Timeago is a jQuery plugin that makes it easy to support automatically
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
*
* @name timeago
* @version 1.1.0
* @requires jQuery v1.2.3+
* @author Ryan McGeary
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
*
* For usage and examples, visit:
* http://timeago.yarp.com/
*
* Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.timeago = function(timestamp) {
if (timestamp instanceof Date) {
return inWords(timestamp);
} else if (typeof timestamp === "string") {
return inWords($.timeago.parse(timestamp));
} else if (typeof timestamp === "number") {
return inWords(new Date(timestamp));
} else {
return inWords($.timeago.datetime(timestamp));
}
};
var $t = $.timeago;
$.extend($.timeago, {
settings: {
refreshMillis: 60000,
allowFuture: false,
strings: {
prefixAgo: null,
prefixFromNow: null,
suffixAgo: "ago",
suffixFromNow: "from now",
seconds: "less than a minute",
minute: "about a minute",
minutes: "%d minutes",
hour: "about an hour",
hours: "about %d hours",
day: "a day",
days: "%d days",
month: "about a month",
months: "%d months",
year: "about a year",
years: "%d years",
wordSeparator: " ",
numbers: []
}
},
inWords: function(distanceMillis) {
var $l = this.settings.strings;
var prefix = $l.prefixAgo;
var suffix = $l.suffixAgo;
if (this.settings.allowFuture) {
if (distanceMillis < 0) {
prefix = $l.prefixFromNow;
suffix = $l.suffixFromNow;
}
}
var seconds = Math.abs(distanceMillis) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
var years = days / 365;
function substitute(stringOrFunction, number) {
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
var value = ($l.numbers && $l.numbers[number]) || number;
return string.replace(/%d/i, value);
}
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
seconds < 90 && substitute($l.minute, 1) ||
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
minutes < 90 && substitute($l.hour, 1) ||
hours < 24 && substitute($l.hours, Math.round(hours)) ||
hours < 42 && substitute($l.day, 1) ||
days < 30 && substitute($l.days, Math.round(days)) ||
days < 45 && substitute($l.month, 1) ||
days < 365 && substitute($l.months, Math.round(days / 30)) ||
years < 1.5 && substitute($l.year, 1) ||
substitute($l.years, Math.round(years));
var separator = $l.wordSeparator || "";
if ($l.wordSeparator === undefined) { separator = " "; }
return $.trim([prefix, words, suffix].join(separator));
},
parse: function(iso8601) {
var s = $.trim(iso8601);
s = s.replace(/\.\d+/,""); // remove milliseconds
s = s.replace(/-/,"/").replace(/-/,"/");
s = s.replace(/T/," ").replace(/Z/," UTC");
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
return new Date(s);
},
datetime: function(elem) {
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
return $t.parse(iso8601);
},
isTime: function(elem) {
// jQuery's `is()` doesn't play well with HTML5 in IE
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
}
});
// functions that can be called via $(el).timeago('action')
// init is default when no action is given
// functions are called with context of a single element
var functions = {
init: function(){
var refresh_el = $.proxy(refresh, this);
refresh_el();
var $s = $t.settings;
if ($s.refreshMillis > 0) {
setInterval(refresh_el, $s.refreshMillis);
}
},
update: function(time){
$(this).data('timeago', { datetime: $t.parse(time) });
refresh.apply(this);
}
};
$.fn.timeago = function(action, options) {
var fn = action ? functions[action] : functions.init;
if(!fn){
throw new Error("Unknown function name '"+ action +"' for timeago");
}
// each over objects here and call the requested function
this.each(function(){
fn.call(this, options);
});
return this;
};
function refresh() {
var data = prepareData(this);
if (!isNaN(data.datetime)) {
$(this).text(inWords(data.datetime));
}
return this;
}
function prepareData(element) {
element = $(element);
if (!element.data("timeago")) {
element.data("timeago", { datetime: $t.datetime(element) });
var text = $.trim(element.text());
if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
element.attr("title", text);
}
}
return element.data("timeago");
}
function inWords(date) {
return $t.inWords(distance(date));
}
function distance(date) {
return (new Date().getTime() - date.getTime());
}
// fix for IE6 suckage
document.createElement("abbr");
document.createElement("time");
}));
Loading
Loading
@@ -53,6 +53,8 @@ $ ->
$('.trigger-submit').on 'change', ->
$(@).parents('form').submit()
 
$("abbr.timeago").timeago()
# Flash
if (flash = $(".flash-container")).length > 0
flash.click -> $(@).fadeOut()
Loading
Loading
Loading
Loading
@@ -30,24 +30,13 @@
Wall.note_ids.push(note.id)
Wall.renderNote(note)
Wall.scrollDown()
$("abbr.timeago").timeago()
 
complete: ->
$('.js-notes-busy').removeClass("loading")
beforeSend: ->
$('.js-notes-busy').addClass("loading")
 
renderNote: (note) ->
author = '<strong class="wall-author">' + note.author.name + '</strong>'
body = '<span class="wall-text">' + note.body + '</span>'
file = ''
if note.attachment
file = '<span class="wall-file"><a href="/files/note/' + note.id + '/' + note.attachment + '">' + note.attachment + '</a></span>'
html = '<li>' + author + body + file + '</li>'
$('ul.notes').append(html)
initRefresh: ->
setInterval("Wall.refresh()", 10000)
 
Loading
Loading
@@ -59,14 +48,9 @@
$('body').scrollTop(notes.height())
 
initForm: ->
form = $('.new_note')
form = $('.wall-note-form')
form.find("#target_type").val('wall')
 
# remove unnecessary fields and buttons
form.find("#note_line_code").remove()
form.find(".js-close-discussion-note-form").remove()
form.find('.js-notify-commit-author').remove()
form.on 'ajax:success', ->
Wall.refresh()
form.find(".js-note-text").val("").trigger("input")
Loading
Loading
@@ -83,3 +67,17 @@
form.find(".js-attachment-filename").text(filename)
form.show()
renderNote: (note) ->
author = '<strong class="wall-author">' + note.author.name + '</strong>'
body = '<span class="wall-text">' + note.body + '</span>'
file = ''
time = '<abbr class="timeago" title="' + note.created_at + '">' + note.created_at + '</time>'
if note.attachment
file = '<span class="wall-file"><a href="/files/note/' + note.id + '/' + note.attachment + '">' + note.attachment + '</a></span>'
html = '<li>' + author + body + file + time + '</li>'
$('ul.notes').append(html)
.wall-page {
.new_note {
.wall-note-form {
@extend .span12;
 
margin: 0;
Loading
Loading
@@ -23,7 +23,14 @@
}
 
.wall-file {
margin-left: 8px;
background: #EEE;
}
abbr {
float: right;
color: #AAA;
border: none;
}
}
}
Loading
Loading
@@ -11,7 +11,7 @@
#{event.note_target_type} ##{truncate event.note_target_id}
 
- elsif event.wall_note?
= link_to 'wall', wall_project_path(event.project)
= link_to 'wall', project_wall_path(event.project)
- else
%strong (deleted)
at
Loading
Loading
%p
New message on
= link_to "Project Wall", wall_project_url(@note.project, anchor: "note_#{@note.id}")
= link_to "Project Wall", project_wall_url(@note.project, anchor: "note_#{@note.id}")
 
= render 'note_message'
New message on the project wall <%= @note.project %>
 
<%= url_for(wall_project_url(@note.project, anchor: "note_#{@note.id}")) %>
<%= url_for(project_wall_url(@note.project, anchor: "note_#{@note.id}")) %>
 
<%= @note.author_name %>
Loading
Loading
Loading
Loading
@@ -2,9 +2,30 @@
%ul.well-list.notes
.notes-busy.js-notes-busy
 
.js-main-target-form
- if can? current_user, :write_note, @project
= render "notes/form"
.note-form-holder
= form_for [@project, @note], remote: true, html: { multipart: true, id: nil, class: "new_note wall-note-form" } do |f|
= note_target_fields
.note_text_and_preview
= f.text_area :note, size: 255, class: 'note_text js-note-text js-gfm-input turn-on'
.note-form-actions
.buttons
= f.submit 'Add Comment', class: "btn comment-btn grouped js-comment-button"
.note-form-option
= label_tag :notify do
= check_box_tag :notify, 1, false
%span.light Notify team via email
.note-form-option
%a.choose-btn.btn.btn-small.js-choose-note-attachment-button
%i.icon-paper-clip
%span Choose File ...
&nbsp;
%span.file_name.js-attachment-filename File name...
= f.file_field :attachment, class: "js-note-attachment-input hide"
.clearfix
 
:javascript
$(function(){
Loading
Loading
Loading
Loading
@@ -161,7 +161,7 @@ module SharedPaths
end
 
Given "I visit my project's wall page" do
visit wall_project_path(@project)
visit project_wall_path(@project)
end
 
Given "I visit my project's wiki page" do
Loading
Loading
Loading
Loading
@@ -198,7 +198,7 @@ describe "Gitlab Flavored Markdown" do
end
 
it "should render in projects#wall", js: true do
visit wall_project_path(project)
visit project_wall_path(project)
within ".new_note.js-main-target-form" do
fill_in "note_note", with: "see ##{issue.id}"
click_button "Add Comment"
Loading
Loading
Loading
Loading
@@ -22,7 +22,7 @@ describe "On a merge request", js: true do
it { within(".js-main-target-form") { should_not have_link("Cancel") } }
 
# notifiactions
it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } }
it { within(".js-main-target-form") { should have_unchecked_field("Notify team via email") } }
it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } }
it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } }
 
Loading
Loading
@@ -127,7 +127,7 @@ describe "On a merge request diff", js: true, focus: true do
it { should have_css(".js-close-discussion-note-form", text: "Cancel") }
 
# notification options
it { should have_checked_field("Notify team via email") }
it { should have_unchecked_field("Notify team via email") }
 
it "shouldn't add a second form for same row" do
find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click")
Loading
Loading
Loading
Loading
@@ -2,84 +2,40 @@ require 'spec_helper'
 
describe "On the project wall", js: true do
let!(:project) { create(:project) }
let!(:commit) { project.repository.commit("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") }
 
before do
login_as :user
project.team << [@user, :master]
visit wall_project_path(project)
visit project_wall_path(project)
end
 
subject { page }
 
describe "the note form" do
# main target form creation
it { should have_css(".js-main-target-form", visible: true, count: 1) }
# button initalization
it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" }
it { within(".js-main-target-form") { should_not have_link("Cancel") } }
# notifiactions
it { within(".js-main-target-form") { should have_checked_field("Notify team via email") } }
it { within(".js-main-target-form") { should_not have_checked_field("Notify commit author") } }
it { within(".js-main-target-form") { should_not have_unchecked_field("Notify commit author") } }
describe "without text" do
it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } }
end
it { should have_css(".wall-note-form", visible: true, count: 1) }
it { find(".wall-note-form input[type=submit]").value.should == "Add Comment" }
it { within(".wall-note-form") { should have_unchecked_field("Notify team via email") } }
 
describe "with text" do
before do
within(".js-main-target-form") do
within(".wall-note-form") do
fill_in "note[note]", with: "This is awesome"
end
end
 
it { within(".js-main-target-form") { should_not have_css(".js-comment-button[disabled]") } }
it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: true) } }
end
describe "with preview" do
before do
within(".js-main-target-form") do
fill_in "note[note]", with: "This is awesome"
find(".js-note-preview-button").trigger("click")
end
end
it { within(".js-main-target-form") { should have_css(".js-note-preview", text: "This is awesome", visible: true) } }
it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } }
it { within(".js-main-target-form") { should have_css(".js-note-edit-button", visible: true) } }
it { within(".wall-note-form") { should_not have_css(".js-comment-button[disabled]") } }
end
end
 
describe "when posting a note" do
before do
within(".js-main-target-form") do
within(".wall-note-form") do
fill_in "note[note]", with: "This is awsome!"
find(".js-note-preview-button").trigger("click")
click_button "Add Comment"
end
end
 
# note added
it { should have_content("This is awsome!") }
# reset form
it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } }
# return from preview
it { within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } }
it { within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } }
it "should be removable" do
find(".js-note-delete").trigger("click")
should_not have_css(".note")
end
it { within(".wall-note-form") { should have_no_field("note[note]", with: "This is awesome!") } }
end
end
Loading
Loading
@@ -95,7 +95,7 @@ describe "Application access" do
end
 
describe "GET /project_code/wall" do
subject { wall_project_path(project) }
subject { project_wall_path(project) }
 
it { should be_allowed_for master }
it { should be_allowed_for reporter }
Loading
Loading
Loading
Loading
@@ -239,7 +239,7 @@ describe Notify do
end
 
describe 'on a project wall' do
let(:note_on_the_wall_path) { wall_project_path(project, anchor: "note_#{note.id}") }
let(:note_on_the_wall_path) { project_wall_path(project, anchor: "note_#{note.id}") }
 
subject { Notify.note_wall_email(recipient.id, note.id) }
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment