homeland 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +32 -0
- data/app/assets/images/reply.png +0 -0
- data/app/assets/javascripts/homeland.coffee +48 -0
- data/app/assets/stylesheets/homeland.scss +84 -0
- data/app/controllers/homeland/application_controller.rb +14 -0
- data/app/controllers/homeland/replies_controller.rb +20 -0
- data/app/controllers/homeland/topics_controller.rb +124 -0
- data/app/helpers/homeland/application_helper.rb +27 -0
- data/app/helpers/homeland/topics_helper.rb +8 -0
- data/app/models/homeland/node.rb +24 -0
- data/app/models/homeland/reply.rb +29 -0
- data/app/models/homeland/section.rb +17 -0
- data/app/models/homeland/topic.rb +43 -0
- data/app/views/homeland/replies/edit.html.erb +28 -0
- data/app/views/homeland/shared/_error_messages.html.erb +11 -0
- data/app/views/homeland/topics/_base.html.erb +4 -0
- data/app/views/homeland/topics/_form.html.erb +23 -0
- data/app/views/homeland/topics/_sidebar.html.erb +65 -0
- data/app/views/homeland/topics/_topic.html.erb +26 -0
- data/app/views/homeland/topics/edit.html.erb +11 -0
- data/app/views/homeland/topics/feed.builder +20 -0
- data/app/views/homeland/topics/index.html.erb +51 -0
- data/app/views/homeland/topics/new.html.erb +11 -0
- data/app/views/homeland/topics/show.html.erb +88 -0
- data/config/routes.rb +16 -0
- data/lib/generators/homeland/install/templates/initializer.rb +8 -0
- data/lib/generators/homeland/install/templates/javascripts/jquery.hotkeys.js +99 -0
- data/lib/generators/homeland/install/templates/javascripts/jquery.timeago.js +147 -0
- data/lib/generators/homeland/install/templates/locales/homeland.zh-CN.yml +14 -0
- data/lib/generators/homeland/install_generator.rb +45 -0
- data/lib/generators/homeland/views_generator.rb +23 -0
- data/lib/homeland.rb +6 -0
- data/lib/homeland/engine.rb +32 -0
- data/lib/homeland/setting.rb +37 -0
- metadata +91 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Homeland
|
3
|
+
class Topic
|
4
|
+
include Mongoid::Document
|
5
|
+
include Mongoid::Timestamps
|
6
|
+
include Mongoid::Paranoia
|
7
|
+
|
8
|
+
field :title
|
9
|
+
field :body
|
10
|
+
field :replied_at , :type => DateTime
|
11
|
+
field :replies_count, :type => Integer, :default => 0
|
12
|
+
field :hits, :type => Integer, :default => 0
|
13
|
+
|
14
|
+
belongs_to :user, :inverse_of => :topics, :class_name => Homeland.user_class.to_s
|
15
|
+
belongs_to :node, :class_name => "Homeland::Node"
|
16
|
+
belongs_to :last_reply_user, :class_name => Homeland.user_class.to_s
|
17
|
+
has_many :replies, :class_name => "Homeland::Reply"
|
18
|
+
|
19
|
+
attr_protected :user_id
|
20
|
+
validates_presence_of :user_id, :title, :body, :node_id
|
21
|
+
|
22
|
+
index :replied_at
|
23
|
+
index :user_id
|
24
|
+
index :node_id
|
25
|
+
|
26
|
+
# scopes
|
27
|
+
scope :last_actived, desc(:replied_at).desc(:_id)
|
28
|
+
scope :recent, desc(:_id)
|
29
|
+
before_save :set_replied_at
|
30
|
+
def set_replied_at
|
31
|
+
self.replied_at = Time.now
|
32
|
+
end
|
33
|
+
|
34
|
+
def hit!
|
35
|
+
self.update_attribute(:hit,{ :inc => 1 })
|
36
|
+
end
|
37
|
+
|
38
|
+
def node_name
|
39
|
+
return "" if self.node.blank?
|
40
|
+
self.node.name
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<% content_for :breadcrumb do %>
|
2
|
+
<span class="current">修改回帖</span>
|
3
|
+
<% end %>
|
4
|
+
<div class="sidebar">
|
5
|
+
<div class="box">
|
6
|
+
回帖所在文章:<br />
|
7
|
+
<a href="<%= topic_path(@reply.topic_id) %>"><%= @reply.topic.title %></a>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
<div class="content">
|
11
|
+
<div class="box">
|
12
|
+
<%= form_for(@reply) do |f| %>
|
13
|
+
<fieldset>
|
14
|
+
<legend>修改回帖</legend>
|
15
|
+
<%= render "shared/error_messages", :target => @reply %>
|
16
|
+
<div class="clearfix">
|
17
|
+
<%= f.label :body %>
|
18
|
+
<div class="input">
|
19
|
+
<%= f.text_area :body, :class => "topic_body_text_area", :rows => "20" %>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
<div class="actions">
|
23
|
+
<button class="btn primary">保存更新</button>
|
24
|
+
<a href="<%= topic_path(@reply.topic_id) %>" class="btn">取消</a>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
28
|
+
</div>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<% if target.errors.any? %>
|
2
|
+
<div class="alert-message block-message error">
|
3
|
+
<a class="close" href="#">×</a>
|
4
|
+
<p><strong>有 <%= target.errors.count %> 处问题导至无法提交:</strong></p>
|
5
|
+
<ul>
|
6
|
+
<% target.errors.full_messages.each do |msg| %>
|
7
|
+
<li><%= msg %></li>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
</div>
|
11
|
+
<% end %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<%= form_for(@topic) do |f| %>
|
2
|
+
<fieldset>
|
3
|
+
<legend><%= @topic.id.blank? ? "新建帖子" : "修改帖子" %></legend>
|
4
|
+
<%= render "shared/error_messages", :target => @topic %>
|
5
|
+
<%= f.hidden_field :node_id %>
|
6
|
+
<div class="clearfix">
|
7
|
+
<%= f.label :title %>
|
8
|
+
<div class="input">
|
9
|
+
<%= f.text_field :title, :class => "span7" %>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
<div class="clearfix">
|
13
|
+
<%= f.label :body %>
|
14
|
+
<div class="input">
|
15
|
+
<%= f.text_area :body, :class => "topic_body_text_area", :style => "height:200px" %>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
<div class="actions">
|
19
|
+
<input type="submit" value="保存" class="btn primary">
|
20
|
+
<a href="<%= @topic.id.blank? ? topics_path : topic_path(@topic) %>" class="btn">取消</a>
|
21
|
+
</div>
|
22
|
+
</fieldset>
|
23
|
+
<% end %>
|
@@ -0,0 +1,65 @@
|
|
1
|
+
<div class="sidebar">
|
2
|
+
<% if ["show","new","edit","node"].index(params[:action]) %>
|
3
|
+
<div class="box">
|
4
|
+
<h2><a href="<%= node_topics_path(@node.id) %>"><%= @node.name %></a></h2>
|
5
|
+
<% if ["new"].index params[:action] %>
|
6
|
+
<p class="sumamry">
|
7
|
+
<%= @node.summary %>
|
8
|
+
</p>
|
9
|
+
<% end %>
|
10
|
+
<div class="content">
|
11
|
+
<a class="btn success" href="<%= new_topic_path(:node => @node.id) %>">发布新帖</a>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
<% elsif params[:action] == "index" %>
|
15
|
+
<div class="box">
|
16
|
+
<h2>社区论坛</h2>
|
17
|
+
<p>
|
18
|
+
发贴请先进入一个节点以后点击“发布新帖”。
|
19
|
+
</p>
|
20
|
+
<p style="text-align:center;">
|
21
|
+
<a href="<%= homeland.feed_topics_url %>" title="用RSS阅读器订阅<%= Setting.app_name %>论坛新贴">
|
22
|
+
<%= image_tag('feed.png', :alt => "订阅#{Setting.app_name}论坛新贴") %></a>
|
23
|
+
</p>
|
24
|
+
</div>
|
25
|
+
<% end %>
|
26
|
+
<%= cache("topic/init_list_sidebar/hot_nodes",:expires_in => 30.minutes) do %>
|
27
|
+
<% if not @hot_nodes.blank? %>
|
28
|
+
<div class="hot_nodes nodes box">
|
29
|
+
<h2>热门节点</h2>
|
30
|
+
<p>
|
31
|
+
<% @hot_nodes.each do |node| %>
|
32
|
+
<a href="<%= node_topics_path(:id => node.id) %>"><%= node.name %></a>
|
33
|
+
<% end %>
|
34
|
+
</p>
|
35
|
+
</div>
|
36
|
+
<% end %>
|
37
|
+
<% end %>
|
38
|
+
<% if current_user and (not @user_last_nodes.blank?) %>
|
39
|
+
<div class="user_last_nodes nodes box">
|
40
|
+
<h2>最近访问节点</h2>
|
41
|
+
<p>
|
42
|
+
<% @user_last_nodes.each do |node| %>
|
43
|
+
<a href="<%= node_topics_path(:id => node.id) %>"><%= node.name %></a>
|
44
|
+
<% end %>
|
45
|
+
</p>
|
46
|
+
</div>
|
47
|
+
<% end %>
|
48
|
+
<% if ["new"].index(params[:action]) %>
|
49
|
+
<div id="topic_new_tip" class="box">
|
50
|
+
<h2>发贴说明</h2>
|
51
|
+
<ol>
|
52
|
+
<li>发布后正文排版会自动安你在文本框里面输入的样子排列.如果里面带有 URL地址,将会自动转变为超级链接。</li>
|
53
|
+
</ol>
|
54
|
+
</div>
|
55
|
+
<% end %>
|
56
|
+
<% if params[:action] == "index" %>
|
57
|
+
<div class="totals box">
|
58
|
+
<h2>统计信息</h2>
|
59
|
+
<ul>
|
60
|
+
<li>贴子数: <%= Homeland::Topic.count %> 篇</li>
|
61
|
+
<li>回贴数: <%= Homeland::Reply.count %> 条</li>
|
62
|
+
</ul>
|
63
|
+
</div>
|
64
|
+
<% end %>
|
65
|
+
</div>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<div class="topic topic_line">
|
2
|
+
<div class="pull-left avatar">
|
3
|
+
<%= user_avatar_tag(topic.user) %>
|
4
|
+
</div>
|
5
|
+
<div class="right_info">
|
6
|
+
<div class="pull-right replies">
|
7
|
+
<a href="<%= topic_path(topic.id) %>#reply<%= topic.replies_count %>" class="count">
|
8
|
+
<%= topic.replies_count %>
|
9
|
+
</a>
|
10
|
+
</div>
|
11
|
+
<div class="infos">
|
12
|
+
<div class="title"><a href="<%= topic_path(topic) %>" title="<%= topic.title %>"><%= truncate(topic.title, :length => 100) %></a></div>
|
13
|
+
<div class="info leader">
|
14
|
+
由 <%= user_name_tag(topic.user) %>
|
15
|
+
在 <a href="<%= node_topics_path(topic.node_id) %>"><%= topic.node.name %></a> 中发起
|
16
|
+
</div>
|
17
|
+
<div class="info time">
|
18
|
+
<% if topic.last_reply_user.blank? %>
|
19
|
+
发布于 <%= timeago(topic.created_at) %>
|
20
|
+
<% else %>
|
21
|
+
最后由 <%= user_name_tag(topic.last_reply_user) %> 回复于 <%= timeago(topic.replied_at) %>
|
22
|
+
<% end %>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
</div>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
xml.instruct! :xml, :version=>"1.0"
|
3
|
+
xml.rss(:version=>"2.0"){
|
4
|
+
xml.channel{
|
5
|
+
xml.title "#{Setting.app_name}"
|
6
|
+
xml.link root_url
|
7
|
+
xml.description("#{Setting.app_name}最新发贴.")
|
8
|
+
xml.language('en-us')
|
9
|
+
for topic in @topics
|
10
|
+
xml.item do
|
11
|
+
xml.title topic.title
|
12
|
+
xml.description format_topic_body(topic.body)
|
13
|
+
xml.author topic.user.name
|
14
|
+
xml.pubDate(topic.created_at.strftime("%a, %d %b %Y %H:%M:%S %z"))
|
15
|
+
xml.link topic_url topic
|
16
|
+
xml.guid topic_url topic
|
17
|
+
end
|
18
|
+
end
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<%= render 'base' %>
|
2
|
+
<% content_for :breadcrumb do %>
|
3
|
+
<% if @node.blank? %>
|
4
|
+
<li>首页</li>
|
5
|
+
<% else %>
|
6
|
+
<li><%= @node.name %></li>
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
9
|
+
<%= render 'sidebar' %>
|
10
|
+
|
11
|
+
<div class="content">
|
12
|
+
<div class="box">
|
13
|
+
<% if !@node.blank? %>
|
14
|
+
<div id="node_info">
|
15
|
+
<p>
|
16
|
+
<h1><%= @node.name %></h1>
|
17
|
+
<span class="total">共有 <%= @node.topics_count %> 个讨论主题</span>
|
18
|
+
</p>
|
19
|
+
</div>
|
20
|
+
<% else %>
|
21
|
+
<h1><%= Setting.app_name %></h1>
|
22
|
+
<% end %>
|
23
|
+
<div class="topics">
|
24
|
+
<%= render :partial => "topic", :collection => @topics %>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<% if params[:action] == "index" %>
|
28
|
+
<div class="more">
|
29
|
+
<a href="<%= recent_topics_path %>">查看更多最近发布的帖子...</a>
|
30
|
+
</div>
|
31
|
+
<% elsif params[:action] == "node" or params[:action] == "search" %>
|
32
|
+
<%= will_paginate @topics %>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
35
|
+
<% if params[:action] == "index" %>
|
36
|
+
<div id="sections" class="box">
|
37
|
+
<h2>节点分类导航</h2>
|
38
|
+
<ul>
|
39
|
+
<% @sections.each do |section| %>
|
40
|
+
<li>
|
41
|
+
<label><%= section.name %></label>
|
42
|
+
<% section.nodes.each do |node| %>
|
43
|
+
<a href="<%= node_topics_path(node.id) %>" title="<%= node.name %>"><%= node.name %></a>
|
44
|
+
<% end %>
|
45
|
+
</li>
|
46
|
+
<% end %>
|
47
|
+
</ul>
|
48
|
+
</div>
|
49
|
+
<% end %>
|
50
|
+
</div>
|
51
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
<%= render 'base' %>
|
2
|
+
<%= content_for :breadcrumb do %>
|
3
|
+
<li class="active">查看贴子</li>
|
4
|
+
<% end %>
|
5
|
+
<%= render 'sidebar' %>
|
6
|
+
<div class="content">
|
7
|
+
<div class="topics box">
|
8
|
+
<div class="topic">
|
9
|
+
<div class="pull-right avatar_large">
|
10
|
+
<%= user_avatar_tag(@topic.user) %>
|
11
|
+
</div>
|
12
|
+
<div class="infos">
|
13
|
+
<h1><%= truncate(@topic.title, :length => 100) %></h1>
|
14
|
+
<div class="info leader">
|
15
|
+
由 <%= user_name_tag(@topic.user) %>
|
16
|
+
在 <a href="<%= node_topics_path(@topic.node_id) %>"><%= @topic.node.name %></a> 节点中发起
|
17
|
+
</div>
|
18
|
+
<div class="info time">
|
19
|
+
<% if @topic.last_reply_user.blank? %>
|
20
|
+
发布于 <%= timeago(@topic.created_at) %>
|
21
|
+
<% else %>
|
22
|
+
最后由 <%= user_name_tag(@topic.last_reply_user) %> 回复于 <%= timeago(@topic.replied_at) %>
|
23
|
+
<% end %>
|
24
|
+
, <%= @topic.hits %> 次阅读
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
<div class="body">
|
29
|
+
<%= format_topic_body(@topic.body) %>
|
30
|
+
</div>
|
31
|
+
<div class="tools">
|
32
|
+
<% if owner?(@topic) %>
|
33
|
+
<a href="<%= edit_topic_path(@topic.id) %>">修改</a>
|
34
|
+
<%= link_to "删除", topic_path(@topic.id), :method => :delete, :confirm => "确定要删除么?" %>
|
35
|
+
<% end %>
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
<% if @replies.blank? %>
|
39
|
+
<div class="no_result">
|
40
|
+
暂无回复。
|
41
|
+
</div>
|
42
|
+
<% else %>
|
43
|
+
<div id="replies" class="box">
|
44
|
+
<div class="total">
|
45
|
+
截止 <%= l @topic.replied_at, :format => :long %>, 共收到 <%= @topic.replies_count %> 条回复
|
46
|
+
</div>
|
47
|
+
<% @replies.each_with_index do |reply,i| %>
|
48
|
+
<div class="reply" id="reply<%= i + 1 %>">
|
49
|
+
<div class="pull-left face"><%= user_avatar_tag(reply.user) %></div>
|
50
|
+
<div class="infos">
|
51
|
+
<div class="info clearfix">
|
52
|
+
<span class="name"><%= user_name_tag(reply.user) %></span>
|
53
|
+
<span class="time"><%= i + 1 %>楼, 回复于 <%= timeago(reply.created_at) %>
|
54
|
+
<% if owner?(reply) %>
|
55
|
+
<a href="<%= edit_reply_path(reply.id) %>">修改</a>
|
56
|
+
<% end %>
|
57
|
+
</span>
|
58
|
+
</div>
|
59
|
+
<div class="body">
|
60
|
+
<%= format_topic_body(reply.body) %>
|
61
|
+
</div>
|
62
|
+
</div>
|
63
|
+
</div>
|
64
|
+
<% end %>
|
65
|
+
</div>
|
66
|
+
<% end %>
|
67
|
+
<% if current_user %>
|
68
|
+
<div id="reply" class="form box">
|
69
|
+
<h4>回复</h4>
|
70
|
+
<%= form_for(Homeland::Reply.new,:url => reply_topic_path(params[:id])) do |f| %>
|
71
|
+
<div class="pull-right">
|
72
|
+
<button type="submit" class="btn primary">提交回复</button><br />
|
73
|
+
<span class="help-inline">Ctrl+Enter</span>
|
74
|
+
</div>
|
75
|
+
<div class="clearfix">
|
76
|
+
<%= f.text_area :body,:class => "span10", :rows => "4" %>
|
77
|
+
</div>
|
78
|
+
|
79
|
+
<% end %>
|
80
|
+
</div>
|
81
|
+
<% else %>
|
82
|
+
<div id="reply" class="form box">
|
83
|
+
<div style="padding:20px;">
|
84
|
+
需要 <a href='/account/sign_in' class="btn primary">登录</a> 后回复方可回复, 如果你还没有账号 <a href="/account/sign_up" class="btn danger"> 点击这里注册</a>。
|
85
|
+
</div>
|
86
|
+
</div>
|
87
|
+
<% end %>
|
88
|
+
</div>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Homeland::Engine.routes.draw do
|
2
|
+
root :to => "topics#index"
|
3
|
+
match "topics/node_:id", :to => "topics#node", :as => :node_topics
|
4
|
+
resources :topics do
|
5
|
+
member do
|
6
|
+
post :reply
|
7
|
+
end
|
8
|
+
collection do
|
9
|
+
get :node
|
10
|
+
get :search
|
11
|
+
get :feed
|
12
|
+
get :recent
|
13
|
+
end
|
14
|
+
end
|
15
|
+
resources :replies
|
16
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Homeland.app_name = "<%= Homeland.app_name %>"
|
2
|
+
# Homeland.user_class = "<%= Homeland.user_class %>"
|
3
|
+
# Homeland.current_user_method = :<%= Homeland.current_user_method %>
|
4
|
+
# Homeland.require_user_method = :<%= Homeland.require_user_method %>
|
5
|
+
# Homeland.user_avatar_method = :<%= Homeland.user_avatar_method %>
|
6
|
+
# Homeland.user_path_method = :<%= Homeland.user_path_method %>
|
7
|
+
# Homeland.per_page = <%= Homeland.per_page.inspect %>
|
8
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery Hotkeys Plugin
|
3
|
+
* Copyright 2010, John Resig
|
4
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
5
|
+
*
|
6
|
+
* Based upon the plugin by Tzury Bar Yochay:
|
7
|
+
* http://github.com/tzuryby/hotkeys
|
8
|
+
*
|
9
|
+
* Original idea by:
|
10
|
+
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
|
11
|
+
*/
|
12
|
+
|
13
|
+
(function(jQuery){
|
14
|
+
|
15
|
+
jQuery.hotkeys = {
|
16
|
+
version: "0.8",
|
17
|
+
|
18
|
+
specialKeys: {
|
19
|
+
8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
|
20
|
+
20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
|
21
|
+
37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
|
22
|
+
96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
|
23
|
+
104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
|
24
|
+
112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
|
25
|
+
120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
|
26
|
+
},
|
27
|
+
|
28
|
+
shiftNums: {
|
29
|
+
"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
|
30
|
+
"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
|
31
|
+
".": ">", "/": "?", "\\": "|"
|
32
|
+
}
|
33
|
+
};
|
34
|
+
|
35
|
+
function keyHandler( handleObj ) {
|
36
|
+
// Only care when a possible input has been specified
|
37
|
+
if ( typeof handleObj.data !== "string" ) {
|
38
|
+
return;
|
39
|
+
}
|
40
|
+
|
41
|
+
var origHandler = handleObj.handler,
|
42
|
+
keys = handleObj.data.toLowerCase().split(" ");
|
43
|
+
|
44
|
+
handleObj.handler = function( event ) {
|
45
|
+
// Don't fire in text-accepting inputs that we didn't directly bind to
|
46
|
+
if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
|
47
|
+
event.target.type === "text") ) {
|
48
|
+
return;
|
49
|
+
}
|
50
|
+
|
51
|
+
// Keypress represents characters, not special keys
|
52
|
+
var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
|
53
|
+
character = String.fromCharCode( event.which ).toLowerCase(),
|
54
|
+
key, modif = "", possible = {};
|
55
|
+
|
56
|
+
// check combinations (alt|ctrl|shift+anything)
|
57
|
+
if ( event.altKey && special !== "alt" ) {
|
58
|
+
modif += "alt+";
|
59
|
+
}
|
60
|
+
|
61
|
+
if ( event.ctrlKey && special !== "ctrl" ) {
|
62
|
+
modif += "ctrl+";
|
63
|
+
}
|
64
|
+
|
65
|
+
// TODO: Need to make sure this works consistently across platforms
|
66
|
+
if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
|
67
|
+
modif += "meta+";
|
68
|
+
}
|
69
|
+
|
70
|
+
if ( event.shiftKey && special !== "shift" ) {
|
71
|
+
modif += "shift+";
|
72
|
+
}
|
73
|
+
|
74
|
+
if ( special ) {
|
75
|
+
possible[ modif + special ] = true;
|
76
|
+
|
77
|
+
} else {
|
78
|
+
possible[ modif + character ] = true;
|
79
|
+
possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
|
80
|
+
|
81
|
+
// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
|
82
|
+
if ( modif === "shift+" ) {
|
83
|
+
possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
88
|
+
if ( possible[ keys[i] ] ) {
|
89
|
+
return origHandler.apply( this, arguments );
|
90
|
+
}
|
91
|
+
}
|
92
|
+
};
|
93
|
+
}
|
94
|
+
|
95
|
+
jQuery.each([ "keydown", "keyup", "keypress" ], function() {
|
96
|
+
jQuery.event.special[ this ] = { add: keyHandler };
|
97
|
+
});
|
98
|
+
|
99
|
+
})( jQuery );
|