homeland 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 );
|