sharkey-web 3.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/Gemfile +4 -0
- data/LICENSE.md +19 -0
- data/README.md +188 -0
- data/Rakefile +8 -0
- data/bin/sharkey-web +9 -0
- data/config.ru +3 -0
- data/lib/sharkey.rb +12 -0
- data/lib/sharkey/app.rb +526 -0
- data/lib/sharkey/importerexporter.rb +79 -0
- data/lib/sharkey/models.rb +295 -0
- data/lib/sharkey/public/css/loading.gif +0 -0
- data/lib/sharkey/public/css/magicsuggest.css +232 -0
- data/lib/sharkey/public/css/nprogress.css +74 -0
- data/lib/sharkey/public/css/styles.css +263 -0
- data/lib/sharkey/public/css/ui.fancytree.css +545 -0
- data/lib/sharkey/public/data/sentences.txt +5 -0
- data/lib/sharkey/public/fonts/Quadrata.eot +0 -0
- data/lib/sharkey/public/fonts/Quadrata.svg +613 -0
- data/lib/sharkey/public/fonts/Quadrata.ttf +0 -0
- data/lib/sharkey/public/fonts/Quadrata.woff +0 -0
- data/lib/sharkey/public/fonts/Quadrata.zip +0 -0
- data/lib/sharkey/public/images/loader.gif +0 -0
- data/lib/sharkey/public/images/sharkey-logo.png +0 -0
- data/lib/sharkey/public/images/sharkey.png +0 -0
- data/lib/sharkey/public/js/ajaxmanager.js +67 -0
- data/lib/sharkey/public/js/keybindings.js +92 -0
- data/lib/sharkey/public/js/lib/bootstrap.min.js +6 -0
- data/lib/sharkey/public/js/lib/jquery-1.9.1.min.js +5 -0
- data/lib/sharkey/public/js/lib/jquery-ui.js +16150 -0
- data/lib/sharkey/public/js/lib/jquery.bootstrap-autohidingnavbar.js +213 -0
- data/lib/sharkey/public/js/lib/jquery.fancytree-all.js +6424 -0
- data/lib/sharkey/public/js/lib/jquery.tagcloud.js +92 -0
- data/lib/sharkey/public/js/lib/magicsuggest.js +1468 -0
- data/lib/sharkey/public/js/lib/mousetrap.min.js +9 -0
- data/lib/sharkey/public/js/lib/nprogress.js +476 -0
- data/lib/sharkey/public/js/page-add-link-autofill.js +102 -0
- data/lib/sharkey/public/js/page-add-link.js +156 -0
- data/lib/sharkey/public/js/page-categories.js +348 -0
- data/lib/sharkey/public/js/page-edit-link.js +103 -0
- data/lib/sharkey/public/js/page-links.js +54 -0
- data/lib/sharkey/public/js/page-settings.js +93 -0
- data/lib/sharkey/public/js/page-tagcloud.js +35 -0
- data/lib/sharkey/public/js/page-tags.js +287 -0
- data/lib/sharkey/public/js/scripts.js +147 -0
- data/lib/sharkey/public/themes/amelia/style.css +7 -0
- data/lib/sharkey/public/themes/bootstrap/style.css +5785 -0
- data/lib/sharkey/public/themes/cerulean/style.css +7 -0
- data/lib/sharkey/public/themes/cosmo/style.css +7 -0
- data/lib/sharkey/public/themes/cyborg/style.css +7 -0
- data/lib/sharkey/public/themes/darkly/style.css +7 -0
- data/lib/sharkey/public/themes/facebook-like/README.md +6 -0
- data/lib/sharkey/public/themes/facebook-like/style.css +6085 -0
- data/lib/sharkey/public/themes/flatly/style.css +7 -0
- data/lib/sharkey/public/themes/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/sharkey/public/themes/fonts/glyphicons-halflings-regular.svg +229 -0
- data/lib/sharkey/public/themes/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/sharkey/public/themes/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/sharkey/public/themes/holo-like/README.md +5 -0
- data/lib/sharkey/public/themes/holo-like/style.css +5997 -0
- data/lib/sharkey/public/themes/journal/style.css +7 -0
- data/lib/sharkey/public/themes/lumen/style.css +7 -0
- data/lib/sharkey/public/themes/readable/style.css +7 -0
- data/lib/sharkey/public/themes/simplex/style.css +7 -0
- data/lib/sharkey/public/themes/slate/style.css +7 -0
- data/lib/sharkey/public/themes/spacelab/style.css +7 -0
- data/lib/sharkey/public/themes/superhero/style.css +7 -0
- data/lib/sharkey/public/themes/united/style.css +7 -0
- data/lib/sharkey/public/themes/yeti/style.css +7 -0
- data/lib/sharkey/setting.rb +74 -0
- data/lib/sharkey/version.rb +5 -0
- data/lib/sharkey/views/404.slim +4 -0
- data/lib/sharkey/views/about.slim +7 -0
- data/lib/sharkey/views/add_link.slim +157 -0
- data/lib/sharkey/views/categories.slim +101 -0
- data/lib/sharkey/views/category.slim +22 -0
- data/lib/sharkey/views/centered.slim +49 -0
- data/lib/sharkey/views/dashboard.slim +107 -0
- data/lib/sharkey/views/dashboard_index.slim +26 -0
- data/lib/sharkey/views/edit_link.slim +121 -0
- data/lib/sharkey/views/help.slim +74 -0
- data/lib/sharkey/views/keybindings.slim +58 -0
- data/lib/sharkey/views/link.slim +30 -0
- data/lib/sharkey/views/links.slim +22 -0
- data/lib/sharkey/views/navbar.slim +68 -0
- data/lib/sharkey/views/settings.slim +74 -0
- data/lib/sharkey/views/settings_index.slim +220 -0
- data/lib/sharkey/views/single_category.slim +37 -0
- data/lib/sharkey/views/single_link.slim +95 -0
- data/lib/sharkey/views/single_tag.slim +33 -0
- data/lib/sharkey/views/tag.slim +22 -0
- data/lib/sharkey/views/tagcloud.slim +54 -0
- data/lib/sharkey/views/tags.slim +99 -0
- data/sharkey-web.gemspec +44 -0
- metadata +324 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
require 'sharkey/models'
|
3
|
+
require 'deps/markio'
|
4
|
+
|
5
|
+
module Sharkey
|
6
|
+
|
7
|
+
# Knows how to import from and export to Netscape Bookmark HTML file.
|
8
|
+
#
|
9
|
+
# This format is commonly used when importing/exporting bookmarks
|
10
|
+
# from most browsers and tools such as Delicious.
|
11
|
+
#
|
12
|
+
# I'm using a modified version of the Ruby Gem Markio
|
13
|
+
# (https://github.com/spajus/markio)
|
14
|
+
#
|
15
|
+
module ImporterExporter
|
16
|
+
module_function
|
17
|
+
|
18
|
+
# Imports all Links, their Tags and Categories from a file.
|
19
|
+
#
|
20
|
+
def import filename
|
21
|
+
|
22
|
+
# TODO Before anything, I should make sure it's a HTML file
|
23
|
+
# and it's not corrupted or anything...
|
24
|
+
|
25
|
+
# Opening and parsing the temporary file, all at once
|
26
|
+
bookmarks = File.open(filename) { |file| Markio::parse(file) }
|
27
|
+
|
28
|
+
# Now we go through all of them, creating the Categories and Links
|
29
|
+
bookmarks.each do |b|
|
30
|
+
|
31
|
+
# First, we make sure the categories of this Link
|
32
|
+
# exist.
|
33
|
+
#
|
34
|
+
# "Folder" is to "Markio" as "Categories" is to "Sharkey"
|
35
|
+
#
|
36
|
+
# `b.folders` is an array of category names, like:
|
37
|
+
#
|
38
|
+
# ["grandparent", "parent", "child"]
|
39
|
+
#
|
40
|
+
# So all we need to do is keep creating from the
|
41
|
+
# first to the last and the whole category hierarchy
|
42
|
+
# will derive.
|
43
|
+
#
|
44
|
+
last_category = nil
|
45
|
+
last_category_parent = nil
|
46
|
+
|
47
|
+
b.folders.each do |category_name|
|
48
|
+
last_category_parent = last_category
|
49
|
+
|
50
|
+
last_category = Sharkey::Category.first_or_create(name: category_name)
|
51
|
+
|
52
|
+
if last_category_parent
|
53
|
+
# last_category_parent.add_child last_category
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Sharkey::Link.create_link(b.title,
|
58
|
+
b.href,
|
59
|
+
b.add_date,
|
60
|
+
b.tags,
|
61
|
+
if last_category
|
62
|
+
then if last_category.id
|
63
|
+
then last_category.id
|
64
|
+
else nil
|
65
|
+
end
|
66
|
+
else nil
|
67
|
+
end,
|
68
|
+
"")
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
# Exports
|
74
|
+
def export filename
|
75
|
+
# Nothing for now
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
@@ -0,0 +1,295 @@
|
|
1
|
+
# This file contains all Models (database-thingies) of this
|
2
|
+
# Application.
|
3
|
+
#
|
4
|
+
# We're using DataMapper as the interface to raw SQLite
|
5
|
+
# databases.
|
6
|
+
#
|
7
|
+
# So here's what we do on this file:
|
8
|
+
#
|
9
|
+
# 1. Initialize DataMapper (settings 'n stuff)
|
10
|
+
# 2. Define the Models
|
11
|
+
# Specify things and columns in databases
|
12
|
+
# 3. Finalize DataMapper (_actually_ create the tables)
|
13
|
+
#
|
14
|
+
|
15
|
+
require 'data_mapper'
|
16
|
+
require 'addressable/uri'
|
17
|
+
|
18
|
+
module Sharkey
|
19
|
+
|
20
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
21
|
+
# Initializing DataMapper
|
22
|
+
|
23
|
+
# Full path to the database file
|
24
|
+
DATABASE_FILE = "#{Dir.pwd}/database.db"
|
25
|
+
DATABASE_PATH = "sqlite3://#{DATABASE_FILE}"
|
26
|
+
|
27
|
+
# By default Strings have at max 50 chars of length
|
28
|
+
# That's hideous! Come on!
|
29
|
+
DataMapper::Property::String.length 255
|
30
|
+
|
31
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
32
|
+
# Creating Models
|
33
|
+
|
34
|
+
# Represents a single HyperLink specified by the user.
|
35
|
+
#
|
36
|
+
class Link
|
37
|
+
# This tells that it is a thing that will get stored
|
38
|
+
# on the database
|
39
|
+
# Below are all the database elements
|
40
|
+
include DataMapper::Resource
|
41
|
+
|
42
|
+
property :id, Serial # Auto-incremented key
|
43
|
+
property :url, URI, :required => true # Actual URL
|
44
|
+
property :title, String # User-specified title
|
45
|
+
property :added_at, DateTime # When this link was added
|
46
|
+
property :comment, Text
|
47
|
+
property :favorite, Boolean, :default => false
|
48
|
+
property :visit_count, Integer, :default => 0
|
49
|
+
property :last_visit, DateTime
|
50
|
+
|
51
|
+
has n, :taggings
|
52
|
+
has n, :tags, :through => :taggings
|
53
|
+
|
54
|
+
has 1, :categorization
|
55
|
+
has 1, :category, :through => :categorization
|
56
|
+
|
57
|
+
# Creates a new Link with specified parameters.
|
58
|
+
#
|
59
|
+
# @note Link#create is a reserved method for DataMapper
|
60
|
+
# it actually inserts it on the database.
|
61
|
+
# This function differs from it on the sense that
|
62
|
+
# it also creates the Tags related to this Link
|
63
|
+
#
|
64
|
+
# @param tags Array of Strings as tag names
|
65
|
+
# @param added_at DateTime object or `nil` for DateTime.now
|
66
|
+
# @param category An ID of _existing_ category
|
67
|
+
#
|
68
|
+
def self.create_link(title, url, added_at, tags, category, comment)
|
69
|
+
# Silently fail
|
70
|
+
return if url.nil?
|
71
|
+
|
72
|
+
# Do not allow relative URLs!
|
73
|
+
# Always assume HTTP
|
74
|
+
if Addressable::URI.parse(url).relative?
|
75
|
+
url = "http://#{url}"
|
76
|
+
end
|
77
|
+
|
78
|
+
# This array will contain the Tags objects
|
79
|
+
# created here
|
80
|
+
the_tags = []
|
81
|
+
if (not tags.nil?) and (not tags.empty?)
|
82
|
+
tags.each do |tag|
|
83
|
+
|
84
|
+
# If Sharkey::Tag exists, return it.
|
85
|
+
# Otherwise, create it
|
86
|
+
the_tags << Sharkey::Tag.first_or_create(name: tag)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Actually populating the database with
|
91
|
+
# a new Link
|
92
|
+
Sharkey::Link.create(title: title || "",
|
93
|
+
url: url,
|
94
|
+
added_at: added_at || DateTime.now,
|
95
|
+
tags: the_tags,
|
96
|
+
category: Sharkey::Category.get(category),
|
97
|
+
comment: comment || "")
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.update_link(id, title, url, tags, category, comment)
|
101
|
+
return if id.nil? or url.nil?
|
102
|
+
|
103
|
+
# This array will contain the Tags objects
|
104
|
+
# created here
|
105
|
+
the_tags = []
|
106
|
+
if (not tags.nil?) and (not tags.empty?)
|
107
|
+
tags.each do |tag|
|
108
|
+
|
109
|
+
# If Sharkey::Tag exists, return it.
|
110
|
+
# Otherwise, create it
|
111
|
+
the_tags << Sharkey::Tag.first_or_create(name: tag)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
Sharkey::Link.get(id).update(title: title,
|
116
|
+
url: url,
|
117
|
+
tags: the_tags,
|
118
|
+
category: Sharkey::Category.get(category),
|
119
|
+
comment: comment || "");
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns all Links that have a Tag with `tag_id`
|
124
|
+
def self.by_tag(tag_id)
|
125
|
+
|
126
|
+
# RANT: I don't know why I couldn't simply do something like
|
127
|
+
# `Sharkey::Link.all(:tag => Sharkey::Tag.get(tag_id))`
|
128
|
+
# it seems so strange!
|
129
|
+
# DataMapper's docs imply that we actually _can_,
|
130
|
+
# so why...?
|
131
|
+
|
132
|
+
taggings = Sharkey::Tagging.all(:tag_id => tag_id)
|
133
|
+
|
134
|
+
Sharkey::Link.all(:taggings => taggings)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Returns all Links that have a Category with `category_id`
|
138
|
+
def self.by_category(category_id)
|
139
|
+
|
140
|
+
# RANT: I don't know why I couldn't simply do something like
|
141
|
+
# `Sharkey::Link.all(:category => Sharkey::Category.get(category_id))`
|
142
|
+
# it seems so strange!
|
143
|
+
# DataMapper's docs imply that we actually _can_,
|
144
|
+
# so why...?
|
145
|
+
|
146
|
+
categorizations = Sharkey::Categorization.all(:category_id => category_id)
|
147
|
+
|
148
|
+
Sharkey::Link.all(:categorization => categorizations)
|
149
|
+
end
|
150
|
+
|
151
|
+
def toggle_favorite
|
152
|
+
self.update(favorite: (not self.favorite));
|
153
|
+
end
|
154
|
+
|
155
|
+
# Tells if this link was ever visited
|
156
|
+
def visited?
|
157
|
+
self.visit_count != 0
|
158
|
+
end
|
159
|
+
|
160
|
+
# Increases the visit count by one
|
161
|
+
def visit
|
162
|
+
self.update(last_visit: DateTime.now);
|
163
|
+
self.update(visit_count: (self.visit_count + 1));
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# Single textual tag Links can have
|
168
|
+
#
|
169
|
+
class Tag
|
170
|
+
include DataMapper::Resource
|
171
|
+
|
172
|
+
property :id, Serial
|
173
|
+
property :name, String, :required => true
|
174
|
+
|
175
|
+
has n, :taggings
|
176
|
+
has n, :links, :through => :taggings
|
177
|
+
end
|
178
|
+
|
179
|
+
# The actual action of tagging Links.
|
180
|
+
#
|
181
|
+
# This is necessary because we can query both
|
182
|
+
# of them:
|
183
|
+
# - All Links of a Tag
|
184
|
+
# - All Tags of a Link
|
185
|
+
#
|
186
|
+
class Tagging
|
187
|
+
include DataMapper::Resource
|
188
|
+
|
189
|
+
belongs_to :tag, :key => true
|
190
|
+
belongs_to :link, :key => true
|
191
|
+
end
|
192
|
+
|
193
|
+
# Category for Links.
|
194
|
+
#
|
195
|
+
# While a Link can have several Tags, it can only
|
196
|
+
# have a single Category.
|
197
|
+
#
|
198
|
+
# Think of it as a folder on your Bookmarks browser.
|
199
|
+
#
|
200
|
+
# A category can have _one_ parent and _many_ children.
|
201
|
+
#
|
202
|
+
class Category
|
203
|
+
include DataMapper::Resource
|
204
|
+
|
205
|
+
property :id, Serial
|
206
|
+
property :name, String, :required => true
|
207
|
+
property :description, Text
|
208
|
+
|
209
|
+
has n, :categorizations
|
210
|
+
has n, :links, :through => :categorizations
|
211
|
+
|
212
|
+
# Access the parent through Category.parent
|
213
|
+
has 1, :categoryParent, :child_key => [ :source_id ]
|
214
|
+
has 1, :parent, self, :through => :categoryParent, :via => :target
|
215
|
+
|
216
|
+
# Access the childs through Category.childs
|
217
|
+
has n, :categoryChilds, :child_key => [ :source_id ]
|
218
|
+
has n, :childs, self, :through => :categoryChilds, :via => :target
|
219
|
+
|
220
|
+
def add_child child
|
221
|
+
return if (child.nil?) or (child == self) or (has_child? child)
|
222
|
+
return if (child.parent) and (child.parent == self)
|
223
|
+
|
224
|
+
self.childs << child
|
225
|
+
child.parent = self
|
226
|
+
|
227
|
+
self.save
|
228
|
+
self
|
229
|
+
end
|
230
|
+
|
231
|
+
def has_child? child
|
232
|
+
self.childs.member? child
|
233
|
+
end
|
234
|
+
|
235
|
+
# Removes the parent/children relationship
|
236
|
+
# @note Does not remove any Categories!
|
237
|
+
def remove_child child
|
238
|
+
throw 'Removing self as child' if child == self
|
239
|
+
|
240
|
+
if self.categoryChilds
|
241
|
+
self.categoryChilds.all(target_id: child.id).destroy
|
242
|
+
end
|
243
|
+
|
244
|
+
if child.categoryParent
|
245
|
+
if child.categoryParent.source_id == self.id
|
246
|
+
child.categoryParent.destroy
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
self.reload
|
251
|
+
self
|
252
|
+
end
|
253
|
+
|
254
|
+
def self.orphans
|
255
|
+
all.select { |me| me.parent.nil? }
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
class CategoryParent
|
260
|
+
include DataMapper::Resource
|
261
|
+
|
262
|
+
belongs_to :source, 'Category', :key => true
|
263
|
+
belongs_to :target, 'Category', :key => true
|
264
|
+
end
|
265
|
+
|
266
|
+
class CategoryChild
|
267
|
+
include DataMapper::Resource
|
268
|
+
|
269
|
+
belongs_to :source, 'Category', :key => true
|
270
|
+
belongs_to :target, 'Category', :key => true
|
271
|
+
end
|
272
|
+
|
273
|
+
class Categorization
|
274
|
+
include DataMapper::Resource
|
275
|
+
|
276
|
+
belongs_to :category, :key => true
|
277
|
+
belongs_to :link, :key => true
|
278
|
+
end
|
279
|
+
|
280
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
281
|
+
# Create Tables
|
282
|
+
|
283
|
+
# This method must be called after ALL models
|
284
|
+
# have been created and BEFORE the app starts
|
285
|
+
DataMapper.finalize
|
286
|
+
|
287
|
+
# Starting out the SQLite Database
|
288
|
+
DataMapper.setup(:default,
|
289
|
+
ENV['DATABASE_URL'] || DATABASE_PATH)
|
290
|
+
|
291
|
+
# Creates Tables if they doesn't exist
|
292
|
+
# Tries to adapt new models to already-existing ones...
|
293
|
+
DataMapper.auto_upgrade!
|
294
|
+
end
|
295
|
+
|
Binary file
|
@@ -0,0 +1,232 @@
|
|
1
|
+
/**
|
2
|
+
* Multiple Selection Component for Bootstrap
|
3
|
+
* Check nicolasbize.github.io/magicsuggest/ for latest updates.
|
4
|
+
*
|
5
|
+
* Author: Nicolas Bize
|
6
|
+
* Created: Feb 8th 2013
|
7
|
+
* Last Updated: Jun 3rd 2014
|
8
|
+
* Version: 2.0.5
|
9
|
+
* Licence: MagicSuggest is licenced under MIT licence (http://opensource.org/licenses/MIT)
|
10
|
+
*/
|
11
|
+
.ms-ctn{
|
12
|
+
position: relative;
|
13
|
+
padding: 5px 12px;
|
14
|
+
height: auto;
|
15
|
+
}
|
16
|
+
.ms-inv{
|
17
|
+
border: 1px solid #CC0000;
|
18
|
+
}
|
19
|
+
.ms-ctn-readonly{
|
20
|
+
cursor: pointer;
|
21
|
+
}
|
22
|
+
.ms-ctn-disabled{
|
23
|
+
cursor: not-allowed;
|
24
|
+
background-color: #eeeeee;
|
25
|
+
}
|
26
|
+
.ms-ctn-bootstrap-focus,
|
27
|
+
.ms-ctn-bootstrap-focus .ms-res-ctn{
|
28
|
+
border-color: rgba(82, 168, 236, 0.8) !important;
|
29
|
+
/* IE6-9 */
|
30
|
+
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6) !important;
|
31
|
+
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6) !important;
|
32
|
+
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6) !important;
|
33
|
+
border-bottom-left-radius: 0;
|
34
|
+
border-bottom-right-radius: 0;
|
35
|
+
}
|
36
|
+
.ms-ctn-focus{
|
37
|
+
border-color: #66afe9;
|
38
|
+
outline: 0;
|
39
|
+
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
|
40
|
+
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
|
41
|
+
}
|
42
|
+
.ms-ctn input{
|
43
|
+
border: 0;
|
44
|
+
box-shadow: none;
|
45
|
+
-webkit-transition: none;
|
46
|
+
outline: none;
|
47
|
+
display: block;
|
48
|
+
padding: 0;
|
49
|
+
line-height: 1.42857143;
|
50
|
+
margin: 1px 0;
|
51
|
+
width: 100%;
|
52
|
+
}
|
53
|
+
.ms-ctn .ms-sel-ctn input{
|
54
|
+
float: left;
|
55
|
+
}
|
56
|
+
.ms-ctn-disabled input{
|
57
|
+
cursor: not-allowed;
|
58
|
+
background-color: #eeeeee;
|
59
|
+
}
|
60
|
+
.ms-ctn .ms-input-readonly{
|
61
|
+
cursor: pointer;
|
62
|
+
}
|
63
|
+
.ms-ctn .ms-empty-text{
|
64
|
+
color: #DDD;
|
65
|
+
}
|
66
|
+
.ms-ctn input:focus{
|
67
|
+
border: 0;
|
68
|
+
box-shadow: none;
|
69
|
+
-webkit-transition: none;
|
70
|
+
background: #FFF;
|
71
|
+
}
|
72
|
+
.ms-ctn input::-ms-clear {
|
73
|
+
width: 0;
|
74
|
+
height: 0;
|
75
|
+
}
|
76
|
+
.ms-ctn .ms-trigger{
|
77
|
+
top: 0;
|
78
|
+
width: 25px;
|
79
|
+
height:100%;
|
80
|
+
position:absolute;
|
81
|
+
right:0;
|
82
|
+
background: transparent;
|
83
|
+
border-left: 1px solid #CCC;
|
84
|
+
cursor: pointer;
|
85
|
+
}
|
86
|
+
.ms-ctn .ms-trigger .ms-trigger-ico {
|
87
|
+
display: inline-block;
|
88
|
+
width: 0;
|
89
|
+
height: 0;
|
90
|
+
vertical-align: top;
|
91
|
+
border-top: 4px solid #333;
|
92
|
+
border-right: 4px solid transparent;
|
93
|
+
border-left: 4px solid transparent;
|
94
|
+
content: "";
|
95
|
+
margin-left: 8px;
|
96
|
+
margin-top: 15px;
|
97
|
+
}
|
98
|
+
.ms-ctn .ms-trigger:hover{
|
99
|
+
background-color: #e6e6e6;
|
100
|
+
}
|
101
|
+
.ms-ctn .ms-trigger:hover .ms-trigger-ico{
|
102
|
+
background-position: 0 -4px;
|
103
|
+
}
|
104
|
+
.ms-ctn-disabled .ms-trigger{
|
105
|
+
cursor: not-allowed;
|
106
|
+
background-color: #eeeeee;
|
107
|
+
}
|
108
|
+
.ms-ctn-bootstrap-focus{
|
109
|
+
border-bottom: 1px solid #CCC;
|
110
|
+
}
|
111
|
+
.ms-res-ctn{
|
112
|
+
width: 100%;
|
113
|
+
display: block;
|
114
|
+
overflow-y: auto;
|
115
|
+
}
|
116
|
+
.ms-res-ctn .ms-res-group{
|
117
|
+
line-height: 23px;
|
118
|
+
text-align: left;
|
119
|
+
padding: 2px 5px;
|
120
|
+
font-weight: bold;
|
121
|
+
border-bottom: 1px dotted #CCC;
|
122
|
+
border-top: 1px solid #CCC;
|
123
|
+
background: #f3edff;
|
124
|
+
color: #333;
|
125
|
+
}
|
126
|
+
.ms-res-ctn .ms-res-item{
|
127
|
+
line-height: 25px;
|
128
|
+
text-align: left;
|
129
|
+
padding: 2px 5px;
|
130
|
+
color: #666;
|
131
|
+
cursor: pointer;
|
132
|
+
}
|
133
|
+
.ms-res-ctn .ms-res-item-grouped{
|
134
|
+
padding-left: 15px;
|
135
|
+
}
|
136
|
+
.ms-res-ctn .ms-res-odd{
|
137
|
+
background: #FAFAFA;
|
138
|
+
}
|
139
|
+
.ms-res-ctn .ms-res-item-active{
|
140
|
+
background-color: #F5F5F5;
|
141
|
+
}
|
142
|
+
.ms-sel-ctn{
|
143
|
+
overflow: auto;
|
144
|
+
line-height: 18px;
|
145
|
+
padding-right: 25px;
|
146
|
+
}
|
147
|
+
.ms-no-trigger .ms-sel-ctn{
|
148
|
+
padding-right: 0;
|
149
|
+
}
|
150
|
+
/** Outer and global tags **/
|
151
|
+
.ms-sel-ctn .ms-sel-item{
|
152
|
+
background: #F3F3F3;
|
153
|
+
color: #999;
|
154
|
+
float: left;
|
155
|
+
font-size: 12px;
|
156
|
+
padding: 3px 5px;
|
157
|
+
border-radius: 3px;
|
158
|
+
border: 1px solid #DDD;
|
159
|
+
margin: 3px 0px 1px 0;
|
160
|
+
}
|
161
|
+
.ms-sel-ctn .ms-sel-invalid{
|
162
|
+
border-color: rgb(248, 165, 165) !important;
|
163
|
+
background: #FDF2F2 !important;
|
164
|
+
}
|
165
|
+
.ms-sel-ctn .ms-sel-item:hover{
|
166
|
+
border: 1px solid #BBB;
|
167
|
+
}
|
168
|
+
/** For inner tags **/
|
169
|
+
.ms-ctn .ms-sel-item{
|
170
|
+
background: #F3F3F3;
|
171
|
+
color: #999;
|
172
|
+
float: left;
|
173
|
+
font-size: 12px;
|
174
|
+
padding: 0 5px;
|
175
|
+
border-radius: 3px;
|
176
|
+
border: 1px solid #DDD;
|
177
|
+
margin: 1px 5px 1px 0;
|
178
|
+
}
|
179
|
+
.ms-ctn .ms-sel-item:hover{
|
180
|
+
border: 1px solid transparent;
|
181
|
+
}
|
182
|
+
.ms-ctn-focus .ms-sel-item:hover{
|
183
|
+
border: 1px solid #BBB;
|
184
|
+
}
|
185
|
+
.ms-sel-ctn .ms-sel-text{
|
186
|
+
background: #FFF;
|
187
|
+
color: #666;
|
188
|
+
padding-right: 0;
|
189
|
+
margin-left: 0;
|
190
|
+
font-size: 14px;
|
191
|
+
font-weight: normal;
|
192
|
+
}
|
193
|
+
.ms-as-string .ms-sel-text{
|
194
|
+
border-color: transparent;
|
195
|
+
}
|
196
|
+
.ms-res-ctn .ms-res-item em{
|
197
|
+
font-style: normal;
|
198
|
+
background: #565656;
|
199
|
+
color: #FFF;
|
200
|
+
}
|
201
|
+
.ms-sel-ctn .ms-sel-text:hover{
|
202
|
+
background: #FFF;
|
203
|
+
}
|
204
|
+
.ms-sel-ctn .ms-sel-item-active{
|
205
|
+
border: 1px solid red;
|
206
|
+
background: #757575;
|
207
|
+
}
|
208
|
+
.ms-stacked .ms-sel-item{
|
209
|
+
float: inherit;
|
210
|
+
}
|
211
|
+
.ms-sel-ctn .ms-sel-item .ms-close-btn{
|
212
|
+
width: 7px;
|
213
|
+
cursor: pointer;
|
214
|
+
height: 7px;
|
215
|
+
float: right;
|
216
|
+
margin: 6px 2px 0 10px;
|
217
|
+
background-image: url(data:image/png;base64,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);
|
218
|
+
background-position: 0 -7px;
|
219
|
+
}
|
220
|
+
.ms-sel-ctn .ms-sel-item .ms-close-btn:hover{
|
221
|
+
background-position: 0 0;
|
222
|
+
}
|
223
|
+
.ms-stacked .ms-sel-item .ms-close-btn {
|
224
|
+
margin-left: 0px;
|
225
|
+
}
|
226
|
+
.ms-helper{
|
227
|
+
color: #AAA;
|
228
|
+
font-size: 10px;
|
229
|
+
position: absolute;
|
230
|
+
top: -17px;
|
231
|
+
right: 0;
|
232
|
+
}
|