[Notice] Announcing the End of Demo Server [Read me]

project: Improve Project Tagging.
* Allow to edit tags on Overview page. * Remove the tag editor on Project Setting page. * Make tag has its own category. * Add defeault tags. * Add a document for Tag Typeahead API.
@e320a5577dfd77ce8db50654022916dfe1f3a178
--- app/assets/stylesheets/less/_page.less
+++ app/assets/stylesheets/less/_page.less
... | ... | @@ -1865,8 +1865,16 @@ |
1865 | 1865 |
padding-bottom: 0; |
1866 | 1866 |
border-bottom: 0 none; |
1867 | 1867 |
} |
1868 |
+ span:not(.label) { |
|
1869 |
+ &:not(:last-child):after { |
|
1870 |
+ content: ", "; |
|
1871 |
+ } |
|
1872 |
+ } |
|
1868 | 1873 |
} |
1869 | 1874 |
} |
1875 |
+ button#edit-toggle { |
|
1876 |
+ float: right; |
|
1877 |
+ } |
|
1870 | 1878 |
} |
1871 | 1879 |
|
1872 | 1880 |
.member-wrap { |
--- app/controllers/ProjectApp.java
+++ app/controllers/ProjectApp.java
... | ... | @@ -390,7 +390,7 @@ |
390 | 390 |
|
391 | 391 |
Map<Long, String> tags = new HashMap<Long, String>(); |
392 | 392 |
for (Tag tag: project.tags) { |
393 |
- tags.put(tag.id, tag.name); |
|
393 |
+ tags.put(tag.id, tag.toString()); |
|
394 | 394 |
} |
395 | 395 |
|
396 | 396 |
return ok(toJson(tags)); |
... | ... | @@ -404,27 +404,53 @@ |
404 | 404 |
*/ |
405 | 405 |
public static Result tag(String ownerName, String projectName) { |
406 | 406 |
Project project = Project.findByNameAndOwner(ownerName, projectName); |
407 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.UPDATE)) { |
|
407 |
+ if (!AccessControl.isAllowed(UserApp.currentUser(), project.tagsAsResource(), Operation.UPDATE)) { |
|
408 | 408 |
return forbidden(); |
409 | 409 |
} |
410 | 410 |
|
411 |
- // Get tag name from the request. Return empty map if the name is not given. |
|
411 |
+ // Get category and name from the request. Return 400 Bad Request if name is not given. |
|
412 | 412 |
Map<String, String[]> data = request().body().asFormUrlEncoded(); |
413 |
+ String category = HttpUtil.getFirstValueFromQuery(data, "category"); |
|
413 | 414 |
String name = HttpUtil.getFirstValueFromQuery(data, "name"); |
414 | 415 |
if (name == null || name.length() == 0) { |
415 |
- return ok(toJson(new HashMap<Long, String>())); |
|
416 |
+ // A tag must have its name. |
|
417 |
+ return badRequest("Tag name is missing."); |
|
416 | 418 |
} |
417 | 419 |
|
418 |
- Tag tag = project.tag(name); |
|
420 |
+ Tag tag = Tag.find |
|
421 |
+ .where().eq("category", category).eq("name", name).findUnique(); |
|
419 | 422 |
|
423 |
+ boolean isCreated = false; |
|
420 | 424 |
if (tag == null) { |
421 |
- // Return empty map if the tag has been already attached. |
|
422 |
- return ok(toJson(new HashMap<Long, String>())); |
|
423 |
- } else { |
|
424 |
- // Return the tag. |
|
425 |
+ // Create new tag if there is no tag which has the given name. |
|
426 |
+ tag = new Tag(category, name); |
|
427 |
+ tag.save(); |
|
428 |
+ isCreated = true; |
|
429 |
+ } |
|
430 |
+ |
|
431 |
+ Boolean isAttached = project.tag(tag); |
|
432 |
+ |
|
433 |
+ if (!isCreated && !isAttached) { |
|
434 |
+ // Something is wrong. This case is not possible. |
|
435 |
+ play.Logger.warn( |
|
436 |
+ "A tag '" + tag + "' is created but failed to attach to project '" |
|
437 |
+ + project + "'."); |
|
438 |
+ } |
|
439 |
+ |
|
440 |
+ if (isAttached) { |
|
441 |
+ // Return the attached tag. The return type is Map<Long, String> |
|
442 |
+ // even if there is only one tag, to unify the return type with |
|
443 |
+ // ProjectApp.tags(). |
|
425 | 444 |
Map<Long, String> tags = new HashMap<Long, String>(); |
426 |
- tags.put(tag.id, tag.name); |
|
427 |
- return ok(toJson(tags)); |
|
445 |
+ tags.put(tag.id, tag.toString()); |
|
446 |
+ if (isCreated) { |
|
447 |
+ return created(toJson(tags)); |
|
448 |
+ } else { |
|
449 |
+ return ok(toJson(tags)); |
|
450 |
+ } |
|
451 |
+ } else { |
|
452 |
+ // Return 204 No Content if the tag has been attached already. |
|
453 |
+ return status(Http.Status.NO_CONTENT); |
|
428 | 454 |
} |
429 | 455 |
} |
430 | 456 |
|
... | ... | @@ -437,7 +463,7 @@ |
437 | 463 |
*/ |
438 | 464 |
public static Result untag(String ownerName, String projectName, Long id) { |
439 | 465 |
Project project = Project.findByNameAndOwner(ownerName, projectName); |
440 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.UPDATE)) { |
|
466 |
+ if (!AccessControl.isAllowed(UserApp.currentUser(), project.tagsAsResource(), Operation.UPDATE)) { |
|
441 | 467 |
return forbidden(); |
442 | 468 |
} |
443 | 469 |
|
--- app/controllers/TagApp.java
+++ app/controllers/TagApp.java
... | ... | @@ -3,40 +3,137 @@ |
3 | 3 |
import com.avaje.ebean.ExpressionList; |
4 | 4 |
import models.Project; |
5 | 5 |
import models.Tag; |
6 |
-import models.enumeration.Operation; |
|
7 | 6 |
import play.mvc.Controller; |
8 | 7 |
import play.mvc.Http; |
9 | 8 |
import play.mvc.Result; |
10 |
-import utils.AccessControl; |
|
11 | 9 |
|
12 | 10 |
import java.util.ArrayList; |
13 |
-import java.util.HashMap; |
|
14 | 11 |
import java.util.List; |
15 |
-import java.util.Map; |
|
16 | 12 |
|
13 |
+import static com.avaje.ebean.Expr.*; |
|
17 | 14 |
import static play.libs.Json.toJson; |
18 | 15 |
|
19 | 16 |
public class TagApp extends Controller { |
20 | 17 |
private static final int MAX_FETCH_TAGS = 1000; |
21 | 18 |
|
22 |
- public static Result tags(String query) { |
|
19 |
+ public enum Context { |
|
20 |
+ PROJECT_TAGGING_TYPEAHEAD, DEFAULT |
|
21 |
+ } |
|
22 |
+ |
|
23 |
+ public static Result tags(String query, String contextAsString, Integer limit) { |
|
23 | 24 |
if (!request().accepts("application/json")) { |
24 | 25 |
return status(Http.Status.NOT_ACCEPTABLE); |
25 | 26 |
} |
26 | 27 |
|
27 |
- ExpressionList<Tag> el = Tag.find.where().contains("name", query); |
|
28 |
- int total = el.findRowCount(); |
|
29 |
- if (total > MAX_FETCH_TAGS) { |
|
30 |
- el.setMaxRows(MAX_FETCH_TAGS); |
|
31 |
- response().setHeader("Content-Range", "items " + MAX_FETCH_TAGS + "/" + total); |
|
28 |
+ List<String> tags; |
|
29 |
+ |
|
30 |
+ Context context = null; |
|
31 |
+ |
|
32 |
+ if (contextAsString == null || contextAsString.isEmpty()) { |
|
33 |
+ context = Context.DEFAULT; |
|
34 |
+ } else { |
|
35 |
+ try { |
|
36 |
+ context = Context.valueOf(contextAsString); |
|
37 |
+ } catch (IllegalArgumentException e) { |
|
38 |
+ return badRequest("Invalid context '" + contextAsString + "'"); |
|
39 |
+ } |
|
32 | 40 |
} |
33 | 41 |
|
34 |
- List<String> tags = new ArrayList<String>(); |
|
35 |
- for (Tag tag: el.findList()) { |
|
36 |
- tags.add(tag.name); |
|
42 |
+ if (limit == null || limit > MAX_FETCH_TAGS) { |
|
43 |
+ limit = MAX_FETCH_TAGS; |
|
44 |
+ } |
|
45 |
+ |
|
46 |
+ switch(context) { |
|
47 |
+ case PROJECT_TAGGING_TYPEAHEAD: |
|
48 |
+ try { |
|
49 |
+ Long projectId = Long.valueOf(request().getQueryString("project_id")); |
|
50 |
+ Project project = Project.find.byId(projectId); |
|
51 |
+ if (project == null) { |
|
52 |
+ return badRequest("No project matches given project_id '" + projectId + "'"); |
|
53 |
+ } |
|
54 |
+ tags = tagsForProjectTagging(query, limit, project); |
|
55 |
+ } catch (IllegalArgumentException e) { |
|
56 |
+ return badRequest("In " + Context.PROJECT_TAGGING_TYPEAHEAD + " context, " + |
|
57 |
+ "the query string should have a project_id field in integer type."); |
|
58 |
+ } |
|
59 |
+ break; |
|
60 |
+ default: |
|
61 |
+ tags = tagsForDefault(query, limit); |
|
62 |
+ break; |
|
37 | 63 |
} |
38 | 64 |
|
39 | 65 |
return ok(toJson(tags)); |
40 | 66 |
} |
41 | 67 |
|
68 |
+ private static List<String> tags(ExpressionList<Tag> el) { |
|
69 |
+ ArrayList<String> tags = new ArrayList<String>(); |
|
70 |
+ |
|
71 |
+ for (Tag tag: el.findList()) { |
|
72 |
+ tags.add(tag.toString()); |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ return tags; |
|
76 |
+ } |
|
77 |
+ |
|
78 |
+ private static List<String> tagsForDefault(String query, int limit) { |
|
79 |
+ ExpressionList<Tag> el = |
|
80 |
+ Tag.find.where().or(icontains("category", query), icontains("name", query)); |
|
81 |
+ |
|
82 |
+ int total = el.findRowCount(); |
|
83 |
+ |
|
84 |
+ if (total > limit) { |
|
85 |
+ el.setMaxRows(limit); |
|
86 |
+ response().setHeader("Content-Range", "items " + limit + "/" + total); |
|
87 |
+ } |
|
88 |
+ |
|
89 |
+ return tags(el); |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ private static List<String> tagsForProjectTagging(String query, int limit, Project project) { |
|
93 |
+ ExpressionList<Tag> el = |
|
94 |
+ Tag.find.where().or(icontains("category", query), icontains("name", query)); |
|
95 |
+ |
|
96 |
+ int total = el.findRowCount(); |
|
97 |
+ |
|
98 |
+ // If the limit is bigger than the total number of resulting tags, juts return all of them. |
|
99 |
+ if (limit > total) { |
|
100 |
+ return tagsForDefault(query, limit); |
|
101 |
+ } |
|
102 |
+ |
|
103 |
+ // If the project has no License tag, list License tags first to |
|
104 |
+ // recommend add one of them. |
|
105 |
+ boolean hasLicenseTags = |
|
106 |
+ Tag.find.where().eq("projects.id", project.id).eq("category", "License") |
|
107 |
+ .findRowCount() > 0; |
|
108 |
+ |
|
109 |
+ if (hasLicenseTags) { |
|
110 |
+ return tagsForDefault(query, limit); |
|
111 |
+ } |
|
112 |
+ |
|
113 |
+ ExpressionList<Tag> elLicense = |
|
114 |
+ Tag.find.where().and(eq("category", "License"), icontains("name", query)); |
|
115 |
+ elLicense.setMaxRows(limit); |
|
116 |
+ List<String> tags = tags(elLicense); |
|
117 |
+ |
|
118 |
+ // If every license tags are listed but quota still remains, then add |
|
119 |
+ // any other tags not in License category to the list. |
|
120 |
+ if (elLicense.findRowCount() < limit) { |
|
121 |
+ ExpressionList<Tag> elExceptLicense = |
|
122 |
+ Tag.find.where().and( |
|
123 |
+ ne("category", "License"), |
|
124 |
+ or(icontains("category", query), icontains("name", query))); |
|
125 |
+ |
|
126 |
+ elExceptLicense.setMaxRows(limit - elLicense.findRowCount()); |
|
127 |
+ |
|
128 |
+ for (Tag tag: elExceptLicense.findList()) { |
|
129 |
+ tags.add(tag.toString()); |
|
130 |
+ } |
|
131 |
+ } |
|
132 |
+ |
|
133 |
+ if (tags.size() < total) { |
|
134 |
+ response().setHeader("Content-Range", "items " + tags.size() + "/" + total); |
|
135 |
+ } |
|
136 |
+ |
|
137 |
+ return tags; |
|
138 |
+ } |
|
42 | 139 |
} |
--- app/models/Project.java
+++ app/models/Project.java
... | ... | @@ -9,6 +9,7 @@ |
9 | 9 |
import javax.validation.constraints.NotNull; |
10 | 10 |
|
11 | 11 |
import com.avaje.ebean.Ebean; |
12 |
+import com.avaje.ebean.ExpressionList; |
|
12 | 13 |
import models.enumeration.ResourceType; |
13 | 14 |
import models.enumeration.RoleType; |
14 | 15 |
import models.resource.Resource; |
... | ... | @@ -308,6 +309,27 @@ |
308 | 309 |
} |
309 | 310 |
} |
310 | 311 |
|
312 |
+ public Resource tagsAsResource() { |
|
313 |
+ return new Resource() { |
|
314 |
+ |
|
315 |
+ @Override |
|
316 |
+ public Long getId() { |
|
317 |
+ return id; |
|
318 |
+ } |
|
319 |
+ |
|
320 |
+ @Override |
|
321 |
+ public Project getProject() { |
|
322 |
+ return Project.this; |
|
323 |
+ } |
|
324 |
+ |
|
325 |
+ @Override |
|
326 |
+ public ResourceType getType() { |
|
327 |
+ return ResourceType.PROJECT_TAGS; |
|
328 |
+ } |
|
329 |
+ |
|
330 |
+ }; |
|
331 |
+ } |
|
332 |
+ |
|
311 | 333 |
public Resource asResource() { |
312 | 334 |
return new Resource() { |
313 | 335 |
|
... | ... | @@ -333,25 +355,17 @@ |
333 | 355 |
return User.findByLoginId(userId); |
334 | 356 |
} |
335 | 357 |
|
336 |
- public Tag tag(String tagName) { |
|
337 |
- // Find a tag by the given name. |
|
338 |
- Tag tag = Tag.find.where().eq("name", tagName).findUnique(); |
|
339 |
- |
|
340 |
- if (tag == null) { |
|
341 |
- // Create new tag if there is no tag which has the given name. |
|
342 |
- tag = new Tag(); |
|
343 |
- tag.name = tagName; |
|
344 |
- tag.save(); |
|
345 |
- } else if (tag.projects.contains(this)) { |
|
346 |
- // Return empty map if the tag has been already attached. |
|
347 |
- return null; |
|
358 |
+ public Boolean tag(Tag tag) { |
|
359 |
+ if (tags.contains(tag)) { |
|
360 |
+ // Return false if the tag has been already attached. |
|
361 |
+ return false; |
|
348 | 362 |
} |
349 | 363 |
|
350 | 364 |
// Attach new tag. |
351 |
- tag.projects.add(this); |
|
352 |
- tag.update(); |
|
365 |
+ tags.add(tag); |
|
366 |
+ update(); |
|
353 | 367 |
|
354 |
- return tag; |
|
368 |
+ return true; |
|
355 | 369 |
} |
356 | 370 |
|
357 | 371 |
public void untag(Tag tag) { |
... | ... | @@ -366,4 +380,8 @@ |
366 | 380 |
public boolean isOwner(User user) { |
367 | 381 |
return owner.toLowerCase().equals(user.loginId.toLowerCase()); |
368 | 382 |
} |
383 |
+ |
|
384 |
+ public String toString() { |
|
385 |
+ return owner + "/" + name; |
|
386 |
+ } |
|
369 | 387 |
} |
--- app/models/Tag.java
+++ app/models/Tag.java
... | ... | @@ -10,6 +10,7 @@ |
10 | 10 |
import java.util.Set; |
11 | 11 |
|
12 | 12 |
@Entity |
13 |
+@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"category", "name"})) |
|
13 | 14 |
public class Tag extends Model { |
14 | 15 |
|
15 | 16 |
/** |
... | ... | @@ -22,23 +23,26 @@ |
22 | 23 |
public Long id; |
23 | 24 |
|
24 | 25 |
@Required |
25 |
- @Column(unique=true) |
|
26 |
+ public String category; |
|
27 |
+ |
|
28 |
+ @Required |
|
26 | 29 |
public String name; |
27 | 30 |
|
28 | 31 |
@ManyToMany(mappedBy="tags") |
29 | 32 |
public Set<Project> projects; |
30 | 33 |
|
31 |
- public static List<Tag> findByProjectId(Long projectId) { |
|
32 |
- return find.where().eq("project.id", projectId).findList(); |
|
33 |
- } |
|
34 |
- |
|
35 |
- public static Tag findById(Long id) { |
|
36 |
- return find.byId(id); |
|
34 |
+ public Tag(String category, String name) { |
|
35 |
+ if (category == null) { |
|
36 |
+ category = "Tag"; |
|
37 |
+ } |
|
38 |
+ this.category = category; |
|
39 |
+ this.name = name; |
|
37 | 40 |
} |
38 | 41 |
|
39 | 42 |
@Transient |
40 | 43 |
public boolean exists() { |
41 |
- return find.where().eq("name", name).findRowCount() > 0; |
|
44 |
+ return find.where().eq("category", category).eq("name", name) |
|
45 |
+ .findRowCount() > 0; |
|
42 | 46 |
} |
43 | 47 |
|
44 | 48 |
@Override |
... | ... | @@ -48,6 +52,11 @@ |
48 | 52 |
project.save(); |
49 | 53 |
} |
50 | 54 |
super.delete(); |
55 |
+ } |
|
56 |
+ |
|
57 |
+ @Override |
|
58 |
+ public String toString() { |
|
59 |
+ return category + " - " + name; |
|
51 | 60 |
} |
52 | 61 |
|
53 | 62 |
public Resource asResource() { |
... | ... | @@ -68,4 +77,4 @@ |
68 | 77 |
} |
69 | 78 |
}; |
70 | 79 |
} |
71 |
-}(파일 끝에 줄바꿈 문자 없음) |
|
80 |
+} |
--- app/models/enumeration/ResourceType.java
+++ app/models/enumeration/ResourceType.java
... | ... | @@ -22,7 +22,8 @@ |
22 | 22 |
ATTACHMENT("attachment"), |
23 | 23 |
ISSUE_COMMENT("issue_comment"), |
24 | 24 |
NONISSUE_COMMENT("nonissue_comment"), |
25 |
- TAG("tag"); |
|
25 |
+ TAG("tag"), |
|
26 |
+ PROJECT_TAGS("project_tags"); |
|
26 | 27 |
|
27 | 28 |
private String resource; |
28 | 29 |
|
--- app/views/layout.scala.html
+++ app/views/layout.scala.html
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 |
<script type="text/javascript" src="@getJSLink("lib/jquery/jquery.zclip.min")"></script> |
26 | 26 |
<script type="text/javascript" src="@getJSLink("lib/jquery/jquery.placeholder.min")"></script> |
27 | 27 |
<script type="text/javascript" src="@getJSLink("lib/bootstrap")"></script> |
28 |
+<script type="text/javascript" src="@getJSLink("lib/bootstrap-better-typeahead")"></script> |
|
28 | 29 |
<script type="text/javascript" src="@getJSLink("lib/rgbcolor")"></script> |
29 | 30 |
<script type="text/javascript" src="@getJSLink("lib/humanize")"></script> |
30 | 31 |
<script type="text/javascript" src="@getJSLink("lib/validate")"></script> |
... | ... | @@ -79,4 +80,4 @@ |
79 | 80 |
@googleAnalytics("UA-40528193-1") |
80 | 81 |
|
81 | 82 |
</body> |
82 |
-</html>(파일 끝에 줄바꿈 문자 없음) |
|
83 |
+</html> |
--- app/views/project/overview.scala.html
+++ app/views/project/overview.scala.html
... | ... | @@ -4,6 +4,7 @@ |
4 | 4 |
@import utils.JodaDateUtil._ |
5 | 5 |
@import utils.TemplateHelper._ |
6 | 6 |
@import models.enumeration._ |
7 |
+@import utils.AccessControl._ |
|
7 | 8 |
|
8 | 9 |
@projectLogoImage = @{ |
9 | 10 |
defining(Attachment.findByContainer(project.asResource)) { files => |
... | ... | @@ -40,29 +41,16 @@ |
40 | 41 |
<div class="inner project-info"> |
41 | 42 |
<header> |
42 | 43 |
<h3>@Messages("project.info")</h3> |
43 |
- <!--<div class="project-status"> |
|
44 |
- <i class="ico ico-like"></i> |
|
45 |
- <span class="num">100</span> |
|
46 |
- <span class="sp">|</span> |
|
47 |
- <i class="ico ico-activity high"></i> |
|
48 |
- </div>--> |
|
44 |
+ @if(isAllowed(UserApp.currentUser(), project.tagsAsResource(), Operation.UPDATE)){ |
|
45 |
+ <button type="button" class="btn btn-small" data-toggle="button" id="tag-editor-toggle">@Messages("button.edit")</button> |
|
46 |
+ } |
|
49 | 47 |
</header> |
50 |
- <ul class="infos"> |
|
51 |
- <li class="info"> |
|
52 |
- <strong>@Messages("project.license") :</strong> GPL v2 |
|
53 |
- </li> |
|
54 |
- <li class="info"> |
|
55 |
- <strong>@Messages("project.tags") :</strong> |
|
56 |
- @for(tag <- project.tags) { |
|
57 |
- <span class="label">@tag.name</span> |
|
58 |
- } |
|
59 |
- </li> |
|
60 |
- <li class="info"> |
|
61 |
- <strong>@Messages("project.codeLanguage") :</strong> Java, JavaScript |
|
62 |
- </li> |
|
63 |
- <li class="info"> |
|
64 |
- <strong>@Messages("project.vcs") :</strong> @project.vcs |
|
65 |
- </li> |
|
48 |
+ <ul class="infos" id="tags"> |
|
49 |
+ <!-- tags are added here by hive.project.Home.js --> |
|
50 |
+ </ul> |
|
51 |
+ <ul> |
|
52 |
+ <input name="newTag" type="text" class="text hidden" style="margin-bottom:0px;" data-provider="typeahead" autocomplete="off"/> |
|
53 |
+ <button id="addTag" type="button" class="btn-transparent n-btn med gray hidden">@Messages("button.add")</button> |
|
66 | 54 |
</ul> |
67 | 55 |
</div> |
68 | 56 |
<div class="inner member-info"> |
... | ... | @@ -126,7 +114,11 @@ |
126 | 114 |
|
127 | 115 |
<script type="text/javascript"> |
128 | 116 |
$(document).ready(function(){ |
129 |
- $hive.loadModule("project.Home"); |
|
117 |
+ $hive.loadModule("project.Home", { |
|
118 |
+ "sURLProjectTags": "@routes.ProjectApp.tags(project.owner, project.name)", |
|
119 |
+ "sURLTags" : "@routes.TagApp.tags()", |
|
120 |
+ "nProjectId" : @project.id |
|
121 |
+ }); |
|
130 | 122 |
}); |
131 | 123 |
</script> |
132 |
-}(파일 끝에 줄바꿈 문자 없음) |
|
124 |
+} |
--- app/views/project/setting.scala.html
+++ app/views/project/setting.scala.html
... | ... | @@ -58,16 +58,6 @@ |
58 | 58 |
</dd> |
59 | 59 |
</dl> |
60 | 60 |
</div> |
61 |
- <div class="box-wrap middle"> |
|
62 |
- <div class="cu-label" style="line-height:30px;">@Messages("project.tags")</div> |
|
63 |
- <div class="cu-desc"> |
|
64 |
- <div id="tags"> |
|
65 |
- <!-- tags will be added here by hive.project.Settings.js --> |
|
66 |
- </div> |
|
67 |
- <input name="newTag" type="text" class="text" style="margin-bottom:0px" data-provider="typeahead" autocomplete="off"/> |
|
68 |
- <button id="addTag" type="button" class="nbtn medium">@Messages("button.add")</button> |
|
69 |
- </div> |
|
70 |
- </div> |
|
71 | 61 |
|
72 | 62 |
<div class="box-wrap middle"> |
73 | 63 |
<div class="cu-label">@Messages("project.shareOption")</div> |
... | ... | @@ -92,10 +82,7 @@ |
92 | 82 |
|
93 | 83 |
<script type="text/javascript"> |
94 | 84 |
$(document).ready(function(){ |
95 |
- $hive.loadModule("project.Setting", { |
|
96 |
- "sURLProjectTags": "@routes.ProjectApp.tags(project.owner, project.name)", |
|
97 |
- "sURLTags" : "@routes.TagApp.tags()" |
|
98 |
- }); |
|
85 |
+ $hive.loadModule("project.Setting"); |
|
99 | 86 |
}); |
100 | 87 |
</script> |
101 | 88 |
|
+++ conf/evolutions/default/11.sql
... | ... | @@ -0,0 +1,322 @@ |
1 | +# --- !Ups | |
2 | + | |
3 | +ALTER TABLE tag ADD COLUMN category VARCHAR(255) NOT NULL; | |
4 | +UPDATE tag SET category='Tag'; | |
5 | +ALTER TABLE tag DROP CONSTRAINT uq_tag_name; | |
6 | +ALTER TABLE tag ADD CONSTRAINT uq_tag_category_name UNIQUE (category, name); | |
7 | + | |
8 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'ALGOL 58'); | |
9 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'ALGOL 60'); | |
10 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'ALGOL 68'); | |
11 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'APL'); | |
12 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'ASP.NET'); | |
13 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'AWK'); | |
14 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'ActionScript'); | |
15 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Ada'); | |
16 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'AppleScript'); | |
17 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'AspectJ'); | |
18 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Assembly language'); | |
19 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'AutoLISP / Visual LISP'); | |
20 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'B'); | |
21 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'BASIC'); | |
22 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'BCPL'); | |
23 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'BREW'); | |
24 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Bash'); | |
25 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Batch (Windows/Dos)'); | |
26 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Bourne shell'); | |
27 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'C#'); | |
28 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'C'); | |
29 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'C++'); | |
30 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'COBOL'); | |
31 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Clipper'); | |
32 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Clojure'); | |
33 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'CobolScript'); | |
34 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'CoffeeScript'); | |
35 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'ColdFusion'); | |
36 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Common Lisp'); | |
37 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Component Pascal'); | |
38 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Curl'); | |
39 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'D'); | |
40 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Dart'); | |
41 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Delphi'); | |
42 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'ECMAScript'); | |
43 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Eiffel'); | |
44 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Emacs Lisp'); | |
45 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Erlang'); | |
46 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'F#'); | |
47 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'F'); | |
48 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Forth'); | |
49 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Fortran'); | |
50 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'FoxBase'); | |
51 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'FoxPro'); | |
52 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Go!'); | |
53 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Go'); | |
54 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Groovy'); | |
55 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Haskell'); | |
56 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Io'); | |
57 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'J'); | |
58 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'JScript'); | |
59 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Java'); | |
60 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'JavaFX Script'); | |
61 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'JavaScript'); | |
62 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'LaTeX'); | |
63 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Lisp'); | |
64 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Logo'); | |
65 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Lua'); | |
66 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'MATLAB'); | |
67 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'MDL'); | |
68 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'ML'); | |
69 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Machine code'); | |
70 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Mathematica'); | |
71 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Maya'); | |
72 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Microcode'); | |
73 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Microsoft Visual C++'); | |
74 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Modula'); | |
75 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Modula-2'); | |
76 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Modula-3'); | |
77 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'OCaml'); | |
78 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Object Lisp'); | |
79 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Object Pascal'); | |
80 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Objective-C'); | |
81 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Opa'); | |
82 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Orc'); | |
83 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PHP'); | |
84 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PL-11'); | |
85 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PL/0'); | |
86 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PL/B'); | |
87 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PL/C'); | |
88 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PL/I'); | |
89 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PL/M'); | |
90 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PL/P'); | |
91 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PL/SQL'); | |
92 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'POP-11'); | |
93 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Pascal'); | |
94 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Perl'); | |
95 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PostScript'); | |
96 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PowerBuilder'); | |
97 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'PowerShell'); | |
98 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Processing.js'); | |
99 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Prolog'); | |
100 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Python'); | |
101 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'QBasic'); | |
102 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'QuakeC'); | |
103 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'R'); | |
104 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'R++'); | |
105 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'REXX'); | |
106 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Ruby'); | |
107 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Rust'); | |
108 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Scala'); | |
109 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Scheme'); | |
110 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Script.NET'); | |
111 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Sed'); | |
112 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Self'); | |
113 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Simula'); | |
114 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Simulink'); | |
115 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Small Basic'); | |
116 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Smalltalk'); | |
117 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Snowball'); | |
118 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Squeak'); | |
119 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'TEX'); | |
120 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Tcl'); | |
121 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'TeX'); | |
122 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'UNITY'); | |
123 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Unix shell'); | |
124 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'UnrealScript'); | |
125 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'VBA'); | |
126 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'VBScript'); | |
127 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'VHDL'); | |
128 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Vala'); | |
129 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Verilog'); | |
130 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual Basic .NET'); | |
131 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual Basic'); | |
132 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual C#'); | |
133 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual DataFlex'); | |
134 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual DialogScript'); | |
135 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual Fortran'); | |
136 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual FoxPro'); | |
137 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual J#'); | |
138 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual J++'); | |
139 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual LISP'); | |
140 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Visual Prolog'); | |
141 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'Windows PowerShell'); | |
142 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'XQuery'); | |
143 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'XSLT'); | |
144 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'bc'); | |
145 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'csh'); | |
146 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'dBase'); | |
147 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'ksh'); | |
148 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'Language ', 'make'); | |
149 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'Apache'); | |
150 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'BSD'); | |
151 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'EPL'); | |
152 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'GPL'); | |
153 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'ISC'); | |
154 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'LGPL'); | |
155 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'MIT'); | |
156 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'MPL v1.1'); | |
157 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'MPL v2.0'); | |
158 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'License', 'Public Domain'); | |
159 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'OS', 'Linux'); | |
160 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'OS', 'OSX'); | |
161 | +INSERT INTO tag (id, category, name) VALUES (nextval('tag_seq'), 'OS', 'Windows'); | |
162 | + | |
163 | +# --- !Downs | |
164 | + | |
165 | +ALTER TABLE tag DROP COLUMN category; | |
166 | +ALTER TABLE tag ADD CONSTRAINT uq_tag_name UNIQUE (name); | |
167 | +ALTER TABLE tag DROP CONSTRAINT uq_tag_category_name; | |
168 | + | |
169 | +DELETE FROM tag WHERE category='Language' AND name='ALGOL 58' | |
170 | +DELETE FROM tag WHERE category='Language' AND name='ALGOL 60' | |
171 | +DELETE FROM tag WHERE category='Language' AND name='ALGOL 68' | |
172 | +DELETE FROM tag WHERE category='Language' AND name='APL' | |
173 | +DELETE FROM tag WHERE category='Language' AND name='ASP.NET' | |
174 | +DELETE FROM tag WHERE category='Language' AND name='AWK' | |
175 | +DELETE FROM tag WHERE category='Language' AND name='ActionScript' | |
176 | +DELETE FROM tag WHERE category='Language' AND name='Ada' | |
177 | +DELETE FROM tag WHERE category='Language' AND name='AppleScript' | |
178 | +DELETE FROM tag WHERE category='Language' AND name='AspectJ' | |
179 | +DELETE FROM tag WHERE category='Language' AND name='Assembly language' | |
180 | +DELETE FROM tag WHERE category='Language' AND name='AutoLISP / Visual LISP' | |
181 | +DELETE FROM tag WHERE category='Language' AND name='B' | |
182 | +DELETE FROM tag WHERE category='Language' AND name='BASIC' | |
183 | +DELETE FROM tag WHERE category='Language' AND name='BCPL' | |
184 | +DELETE FROM tag WHERE category='Language' AND name='BREW' | |
185 | +DELETE FROM tag WHERE category='Language' AND name='Bash' | |
186 | +DELETE FROM tag WHERE category='Language' AND name='Batch (Windows/Dos)' | |
187 | +DELETE FROM tag WHERE category='Language' AND name='Bourne shell' | |
188 | +DELETE FROM tag WHERE category='Language' AND name='C#' | |
189 | +DELETE FROM tag WHERE category='Language' AND name='C' | |
190 | +DELETE FROM tag WHERE category='Language' AND name='C++' | |
191 | +DELETE FROM tag WHERE category='Language' AND name='COBOL' | |
192 | +DELETE FROM tag WHERE category='Language' AND name='Clipper' | |
193 | +DELETE FROM tag WHERE category='Language' AND name='Clojure' | |
194 | +DELETE FROM tag WHERE category='Language' AND name='CobolScript' | |
195 | +DELETE FROM tag WHERE category='Language' AND name='CoffeeScript' | |
196 | +DELETE FROM tag WHERE category='Language' AND name='ColdFusion' | |
197 | +DELETE FROM tag WHERE category='Language' AND name='Common Lisp' | |
198 | +DELETE FROM tag WHERE category='Language' AND name='Component Pascal' | |
199 | +DELETE FROM tag WHERE category='Language' AND name='Curl' | |
200 | +DELETE FROM tag WHERE category='Language' AND name='D' | |
201 | +DELETE FROM tag WHERE category='Language' AND name='Dart' | |
202 | +DELETE FROM tag WHERE category='Language' AND name='Delphi' | |
203 | +DELETE FROM tag WHERE category='Language' AND name='ECMAScript' | |
204 | +DELETE FROM tag WHERE category='Language' AND name='Eiffel' | |
205 | +DELETE FROM tag WHERE category='Language' AND name='Emacs Lisp' | |
206 | +DELETE FROM tag WHERE category='Language' AND name='Erlang' | |
207 | +DELETE FROM tag WHERE category='Language' AND name='F#' | |
208 | +DELETE FROM tag WHERE category='Language' AND name='F' | |
209 | +DELETE FROM tag WHERE category='Language' AND name='Forth' | |
210 | +DELETE FROM tag WHERE category='Language' AND name='Fortran' | |
211 | +DELETE FROM tag WHERE category='Language' AND name='FoxBase' | |
212 | +DELETE FROM tag WHERE category='Language' AND name='FoxPro' | |
213 | +DELETE FROM tag WHERE category='Language' AND name='Go!' | |
214 | +DELETE FROM tag WHERE category='Language' AND name='Go' | |
215 | +DELETE FROM tag WHERE category='Language' AND name='Groovy' | |
216 | +DELETE FROM tag WHERE category='Language' AND name='Haskell' | |
217 | +DELETE FROM tag WHERE category='Language' AND name='Io' | |
218 | +DELETE FROM tag WHERE category='Language' AND name='J' | |
219 | +DELETE FROM tag WHERE category='Language' AND name='JScript' | |
220 | +DELETE FROM tag WHERE category='Language' AND name='Java' | |
221 | +DELETE FROM tag WHERE category='Language' AND name='JavaFX Script' | |
222 | +DELETE FROM tag WHERE category='Language' AND name='JavaScript' | |
223 | +DELETE FROM tag WHERE category='Language' AND name='LaTeX' | |
224 | +DELETE FROM tag WHERE category='Language' AND name='Lisp' | |
225 | +DELETE FROM tag WHERE category='Language' AND name='Logo' | |
226 | +DELETE FROM tag WHERE category='Language' AND name='Lua' | |
227 | +DELETE FROM tag WHERE category='Language' AND name='MATLAB' | |
228 | +DELETE FROM tag WHERE category='Language' AND name='MDL' | |
229 | +DELETE FROM tag WHERE category='Language' AND name='ML' | |
230 | +DELETE FROM tag WHERE category='Language' AND name='Machine code' | |
231 | +DELETE FROM tag WHERE category='Language' AND name='Mathematica' | |
232 | +DELETE FROM tag WHERE category='Language' AND name='Maya' | |
233 | +DELETE FROM tag WHERE category='Language' AND name='Microcode' | |
234 | +DELETE FROM tag WHERE category='Language' AND name='Microsoft Visual C++' | |
235 | +DELETE FROM tag WHERE category='Language' AND name='Modula' | |
236 | +DELETE FROM tag WHERE category='Language' AND name='Modula-2' | |
237 | +DELETE FROM tag WHERE category='Language' AND name='Modula-3' | |
238 | +DELETE FROM tag WHERE category='Language' AND name='OCaml' | |
239 | +DELETE FROM tag WHERE category='Language' AND name='Object Lisp' | |
240 | +DELETE FROM tag WHERE category='Language' AND name='Object Pascal' | |
241 | +DELETE FROM tag WHERE category='Language' AND name='Objective-C' | |
242 | +DELETE FROM tag WHERE category='Language' AND name='Opa' | |
243 | +DELETE FROM tag WHERE category='Language' AND name='Orc' | |
244 | +DELETE FROM tag WHERE category='Language' AND name='PHP' | |
245 | +DELETE FROM tag WHERE category='Language' AND name='PL-11' | |
246 | +DELETE FROM tag WHERE category='Language' AND name='PL/0' | |
247 | +DELETE FROM tag WHERE category='Language' AND name='PL/B' | |
248 | +DELETE FROM tag WHERE category='Language' AND name='PL/C' | |
249 | +DELETE FROM tag WHERE category='Language' AND name='PL/I' | |
250 | +DELETE FROM tag WHERE category='Language' AND name='PL/M' | |
251 | +DELETE FROM tag WHERE category='Language' AND name='PL/P' | |
252 | +DELETE FROM tag WHERE category='Language' AND name='PL/SQL' | |
253 | +DELETE FROM tag WHERE category='Language' AND name='POP-11' | |
254 | +DELETE FROM tag WHERE category='Language' AND name='Pascal' | |
255 | +DELETE FROM tag WHERE category='Language' AND name='Perl' | |
256 | +DELETE FROM tag WHERE category='Language' AND name='PostScript' | |
257 | +DELETE FROM tag WHERE category='Language' AND name='PowerBuilder' | |
258 | +DELETE FROM tag WHERE category='Language' AND name='PowerShell' | |
259 | +DELETE FROM tag WHERE category='Language' AND name='Processing.js' | |
260 | +DELETE FROM tag WHERE category='Language' AND name='Prolog' | |
261 | +DELETE FROM tag WHERE category='Language' AND name='Python' | |
262 | +DELETE FROM tag WHERE category='Language' AND name='QBasic' | |
263 | +DELETE FROM tag WHERE category='Language' AND name='QuakeC' | |
264 | +DELETE FROM tag WHERE category='Language' AND name='R' | |
265 | +DELETE FROM tag WHERE category='Language' AND name='R++' | |
266 | +DELETE FROM tag WHERE category='Language' AND name='REXX' | |
267 | +DELETE FROM tag WHERE category='Language' AND name='Ruby' | |
268 | +DELETE FROM tag WHERE category='Language' AND name='Rust' | |
269 | +DELETE FROM tag WHERE category='Language' AND name='Scala' | |
270 | +DELETE FROM tag WHERE category='Language' AND name='Scheme' | |
271 | +DELETE FROM tag WHERE category='Language' AND name='Script.NET' | |
272 | +DELETE FROM tag WHERE category='Language' AND name='Sed' | |
273 | +DELETE FROM tag WHERE category='Language' AND name='Self' | |
274 | +DELETE FROM tag WHERE category='Language' AND name='Simula' | |
275 | +DELETE FROM tag WHERE category='Language' AND name='Simulink' | |
276 | +DELETE FROM tag WHERE category='Language' AND name='Small Basic' | |
277 | +DELETE FROM tag WHERE category='Language' AND name='Smalltalk' | |
278 | +DELETE FROM tag WHERE category='Language' AND name='Snowball' | |
279 | +DELETE FROM tag WHERE category='Language' AND name='Squeak' | |
280 | +DELETE FROM tag WHERE category='Language' AND name='TEX' | |
281 | +DELETE FROM tag WHERE category='Language' AND name='Tcl' | |
282 | +DELETE FROM tag WHERE category='Language' AND name='TeX' | |
283 | +DELETE FROM tag WHERE category='Language' AND name='UNITY' | |
284 | +DELETE FROM tag WHERE category='Language' AND name='Unix shell' | |
285 | +DELETE FROM tag WHERE category='Language' AND name='UnrealScript' | |
286 | +DELETE FROM tag WHERE category='Language' AND name='VBA' | |
287 | +DELETE FROM tag WHERE category='Language' AND name='VBScript' | |
288 | +DELETE FROM tag WHERE category='Language' AND name='VHDL' | |
289 | +DELETE FROM tag WHERE category='Language' AND name='Vala' | |
290 | +DELETE FROM tag WHERE category='Language' AND name='Verilog' | |
291 | +DELETE FROM tag WHERE category='Language' AND name='Visual Basic .NET' | |
292 | +DELETE FROM tag WHERE category='Language' AND name='Visual Basic' | |
293 | +DELETE FROM tag WHERE category='Language' AND name='Visual C#' | |
294 | +DELETE FROM tag WHERE category='Language' AND name='Visual DataFlex' | |
295 | +DELETE FROM tag WHERE category='Language' AND name='Visual DialogScript' | |
296 | +DELETE FROM tag WHERE category='Language' AND name='Visual Fortran' | |
297 | +DELETE FROM tag WHERE category='Language' AND name='Visual FoxPro' | |
298 | +DELETE FROM tag WHERE category='Language' AND name='Visual J#' | |
299 | +DELETE FROM tag WHERE category='Language' AND name='Visual J++' | |
300 | +DELETE FROM tag WHERE category='Language' AND name='Visual LISP' | |
301 | +DELETE FROM tag WHERE category='Language' AND name='Visual Prolog' | |
302 | +DELETE FROM tag WHERE category='Language' AND name='Windows PowerShell' | |
303 | +DELETE FROM tag WHERE category='Language' AND name='XQuery' | |
304 | +DELETE FROM tag WHERE category='Language' AND name='XSLT' | |
305 | +DELETE FROM tag WHERE category='Language' AND name='bc' | |
306 | +DELETE FROM tag WHERE category='Language' AND name='csh' | |
307 | +DELETE FROM tag WHERE category='Language' AND name='dBase' | |
308 | +DELETE FROM tag WHERE category='Language' AND name='ksh' | |
309 | +DELETE FROM tag WHERE category='Language' AND name='make' | |
310 | +DELETE FROM tag WHERE category='License' AND name='Apache' | |
311 | +DELETE FROM tag WHERE category='License' AND name='BSD' | |
312 | +DELETE FROM tag WHERE category='License' AND name='EPL' | |
313 | +DELETE FROM tag WHERE category='License' AND name='GPL' | |
314 | +DELETE FROM tag WHERE category='License' AND name='ISC' | |
315 | +DELETE FROM tag WHERE category='License' AND name='LGPL' | |
316 | +DELETE FROM tag WHERE category='License' AND name='MIT' | |
317 | +DELETE FROM tag WHERE category='License' AND name='MPL v1.1' | |
318 | +DELETE FROM tag WHERE category='License' AND name='MPL v2.0' | |
319 | +DELETE FROM tag WHERE category='License' AND name='Public Domain' | |
320 | +DELETE FROM tag WHERE category='OS' AND name='Linux' | |
321 | +DELETE FROM tag WHERE category='OS' AND name='OSX' | |
322 | +DELETE FROM tag WHERE category='OS' AND name='Windows' |
--- conf/initial-data.yml
+++ conf/initial-data.yml
... | ... | @@ -22,3 +22,471 @@ |
22 | 22 |
- !!models.Role |
23 | 23 |
name: member |
24 | 24 |
active: true |
25 |
+ |
|
26 |
+# Tags |
|
27 |
+tags: |
|
28 |
+ - !!models.Tag |
|
29 |
+ category: OS |
|
30 |
+ name: Windows |
|
31 |
+ - !!models.Tag |
|
32 |
+ category: OS |
|
33 |
+ name: OSX |
|
34 |
+ - !!models.Tag |
|
35 |
+ category: OS |
|
36 |
+ name: Linux |
|
37 |
+ - !!models.Tag |
|
38 |
+ category: Language |
|
39 |
+ name: ActionScript |
|
40 |
+ - !!models.Tag |
|
41 |
+ category: Language |
|
42 |
+ name: Ada |
|
43 |
+ - !!models.Tag |
|
44 |
+ category: Language |
|
45 |
+ name: ALGOL 58 |
|
46 |
+ - !!models.Tag |
|
47 |
+ category: Language |
|
48 |
+ name: ALGOL 60 |
|
49 |
+ - !!models.Tag |
|
50 |
+ category: Language |
|
51 |
+ name: ALGOL 68 |
|
52 |
+ - !!models.Tag |
|
53 |
+ category: Language |
|
54 |
+ name: APL |
|
55 |
+ - !!models.Tag |
|
56 |
+ category: Language |
|
57 |
+ name: AppleScript |
|
58 |
+ - !!models.Tag |
|
59 |
+ category: Language |
|
60 |
+ name: AspectJ |
|
61 |
+ - !!models.Tag |
|
62 |
+ category: Language |
|
63 |
+ name: ASP.NET |
|
64 |
+ - !!models.Tag |
|
65 |
+ category: Language |
|
66 |
+ name: Assembly language |
|
67 |
+ - !!models.Tag |
|
68 |
+ category: Language |
|
69 |
+ name: AutoLISP / Visual LISP |
|
70 |
+ - !!models.Tag |
|
71 |
+ category: Language |
|
72 |
+ name: Visual LISP |
|
73 |
+ - !!models.Tag |
|
74 |
+ category: Language |
|
75 |
+ name: AWK |
|
76 |
+ - !!models.Tag |
|
77 |
+ category: Language |
|
78 |
+ name: B |
|
79 |
+ - !!models.Tag |
|
80 |
+ category: Language |
|
81 |
+ name: Bash |
|
82 |
+ - !!models.Tag |
|
83 |
+ category: Language |
|
84 |
+ name: BASIC |
|
85 |
+ - !!models.Tag |
|
86 |
+ category: Language |
|
87 |
+ name: bc |
|
88 |
+ - !!models.Tag |
|
89 |
+ category: Language |
|
90 |
+ name: BCPL |
|
91 |
+ - !!models.Tag |
|
92 |
+ category: Language |
|
93 |
+ name: Batch (Windows/Dos) |
|
94 |
+ - !!models.Tag |
|
95 |
+ category: Language |
|
96 |
+ name: Bourne shell |
|
97 |
+ - !!models.Tag |
|
98 |
+ category: Language |
|
99 |
+ name: BREW |
|
100 |
+ - !!models.Tag |
|
101 |
+ category: Language |
|
102 |
+ name: C |
|
103 |
+ - !!models.Tag |
|
104 |
+ category: Language |
|
105 |
+ name: C++ |
|
106 |
+ - !!models.Tag |
|
107 |
+ category: Language |
|
108 |
+ name: C# |
|
109 |
+ - !!models.Tag |
|
110 |
+ category: Language |
|
111 |
+ name: Clipper |
|
112 |
+ - !!models.Tag |
|
113 |
+ category: Language |
|
114 |
+ name: Clojure |
|
115 |
+ - !!models.Tag |
|
116 |
+ category: Language |
|
117 |
+ name: COBOL |
|
118 |
+ - !!models.Tag |
|
119 |
+ category: Language |
|
120 |
+ name: CobolScript |
|
121 |
+ - !!models.Tag |
|
122 |
+ category: Language |
|
123 |
+ name: CoffeeScript |
|
124 |
+ - !!models.Tag |
|
125 |
+ category: Language |
|
126 |
+ name: ColdFusion |
|
127 |
+ - !!models.Tag |
|
128 |
+ category: Language |
|
129 |
+ name: Common Lisp |
|
130 |
+ - !!models.Tag |
|
131 |
+ category: Language |
|
132 |
+ name: Component Pascal |
|
133 |
+ - !!models.Tag |
|
134 |
+ category: Language |
|
135 |
+ name: csh |
|
136 |
+ - !!models.Tag |
|
137 |
+ category: Language |
|
138 |
+ name: Curl |
|
139 |
+ - !!models.Tag |
|
140 |
+ category: Language |
|
141 |
+ name: D |
|
142 |
+ - !!models.Tag |
|
143 |
+ category: Language |
|
144 |
+ name: Dart |
|
145 |
+ - !!models.Tag |
|
146 |
+ category: Language |
|
147 |
+ name: dBase |
|
148 |
+ - !!models.Tag |
|
149 |
+ category: Language |
|
150 |
+ name: Delphi |
|
151 |
+ - !!models.Tag |
|
152 |
+ category: Language |
|
153 |
+ name: ECMAScript |
|
154 |
+ - !!models.Tag |
|
155 |
+ category: Language |
|
156 |
+ name: Eiffel |
|
157 |
+ - !!models.Tag |
|
158 |
+ category: Language |
|
159 |
+ name: Emacs Lisp |
|
160 |
+ - !!models.Tag |
|
161 |
+ category: Language |
|
162 |
+ name: Erlang |
|
163 |
+ - !!models.Tag |
|
164 |
+ category: Language |
|
165 |
+ name: F |
|
166 |
+ - !!models.Tag |
|
167 |
+ category: Language |
|
168 |
+ name: F# |
|
169 |
+ - !!models.Tag |
|
170 |
+ category: Language |
|
171 |
+ name: Forth |
|
172 |
+ - !!models.Tag |
|
173 |
+ category: Language |
|
174 |
+ name: Fortran |
|
175 |
+ - !!models.Tag |
|
176 |
+ category: Language |
|
177 |
+ name: FoxBase |
|
178 |
+ - !!models.Tag |
|
179 |
+ category: Language |
|
180 |
+ name: FoxPro |
|
181 |
+ - !!models.Tag |
|
182 |
+ category: Language |
|
183 |
+ name: Go |
|
184 |
+ - !!models.Tag |
|
185 |
+ category: Language |
|
186 |
+ name: Go! |
|
187 |
+ - !!models.Tag |
|
188 |
+ category: Language |
|
189 |
+ name: Groovy |
|
190 |
+ - !!models.Tag |
|
191 |
+ category: Language |
|
192 |
+ name: Haskell |
|
193 |
+ - !!models.Tag |
|
194 |
+ category: Language |
|
195 |
+ name: Io |
|
196 |
+ - !!models.Tag |
|
197 |
+ category: Language |
|
198 |
+ name: J |
|
199 |
+ - !!models.Tag |
|
200 |
+ category: Language |
|
201 |
+ name: Java |
|
202 |
+ - !!models.Tag |
|
203 |
+ category: Language |
|
204 |
+ name: JavaScript |
|
205 |
+ - !!models.Tag |
|
206 |
+ category: Language |
|
207 |
+ name: JScript |
|
208 |
+ - !!models.Tag |
|
209 |
+ category: Language |
|
210 |
+ name: JavaFX Script |
|
211 |
+ - !!models.Tag |
|
212 |
+ category: Language |
|
213 |
+ name: ksh |
|
214 |
+ - !!models.Tag |
|
215 |
+ category: Language |
|
216 |
+ name: LaTeX |
|
217 |
+ - !!models.Tag |
|
218 |
+ category: Language |
|
219 |
+ name: Lisp |
|
220 |
+ - !!models.Tag |
|
221 |
+ category: Language |
|
222 |
+ name: Logo |
|
223 |
+ - !!models.Tag |
|
224 |
+ category: Language |
|
225 |
+ name: Lua |
|
226 |
+ - !!models.Tag |
|
227 |
+ category: Language |
|
228 |
+ name: Machine code |
|
229 |
+ - !!models.Tag |
|
230 |
+ category: Language |
|
231 |
+ name: make |
|
232 |
+ - !!models.Tag |
|
233 |
+ category: Language |
|
234 |
+ name: Mathematica |
|
235 |
+ - !!models.Tag |
|
236 |
+ category: Language |
|
237 |
+ name: MATLAB |
|
238 |
+ - !!models.Tag |
|
239 |
+ category: Language |
|
240 |
+ name: Maya |
|
241 |
+ - !!models.Tag |
|
242 |
+ category: Language |
|
243 |
+ name: MDL |
|
244 |
+ - !!models.Tag |
|
245 |
+ category: Language |
|
246 |
+ name: Microcode |
|
247 |
+ - !!models.Tag |
|
248 |
+ category: Language |
|
249 |
+ name: ML |
|
250 |
+ - !!models.Tag |
|
251 |
+ category: Language |
|
252 |
+ name: Modula |
|
253 |
+ - !!models.Tag |
|
254 |
+ category: Language |
|
255 |
+ name: Modula-2 |
|
256 |
+ - !!models.Tag |
|
257 |
+ category: Language |
|
258 |
+ name: Modula-3 |
|
259 |
+ - !!models.Tag |
|
260 |
+ category: Language |
|
261 |
+ name: Object Lisp |
|
262 |
+ - !!models.Tag |
|
263 |
+ category: Language |
|
264 |
+ name: Object Pascal |
|
265 |
+ - !!models.Tag |
|
266 |
+ category: Language |
|
267 |
+ name: Objective-C |
|
268 |
+ - !!models.Tag |
|
269 |
+ category: Language |
|
270 |
+ name: OCaml |
|
271 |
+ - !!models.Tag |
|
272 |
+ category: Language |
|
273 |
+ name: Opa |
|
274 |
+ - !!models.Tag |
|
275 |
+ category: Language |
|
276 |
+ name: Orc |
|
277 |
+ - !!models.Tag |
|
278 |
+ category: Language |
|
279 |
+ name: Pascal |
|
280 |
+ - !!models.Tag |
|
281 |
+ category: Language |
|
282 |
+ name: Perl |
|
283 |
+ - !!models.Tag |
|
284 |
+ category: Language |
|
285 |
+ name: PHP |
|
286 |
+ - !!models.Tag |
|
287 |
+ category: Language |
|
288 |
+ name: PL-11 |
|
289 |
+ - !!models.Tag |
|
290 |
+ category: Language |
|
291 |
+ name: PL/0 |
|
292 |
+ - !!models.Tag |
|
293 |
+ category: Language |
|
294 |
+ name: PL/B |
|
295 |
+ - !!models.Tag |
|
296 |
+ category: Language |
|
297 |
+ name: PL/C |
|
298 |
+ - !!models.Tag |
|
299 |
+ category: Language |
|
300 |
+ name: PL/I |
|
301 |
+ - !!models.Tag |
|
302 |
+ category: Language |
|
303 |
+ name: PL/M |
|
304 |
+ - !!models.Tag |
|
305 |
+ category: Language |
|
306 |
+ name: PL/P |
|
307 |
+ - !!models.Tag |
|
308 |
+ category: Language |
|
309 |
+ name: PL/SQL |
|
310 |
+ - !!models.Tag |
|
311 |
+ category: Language |
|
312 |
+ name: POP-11 |
|
313 |
+ - !!models.Tag |
|
314 |
+ category: Language |
|
315 |
+ name: PostScript |
|
316 |
+ - !!models.Tag |
|
317 |
+ category: Language |
|
318 |
+ name: PowerBuilder |
|
319 |
+ - !!models.Tag |
|
320 |
+ category: Language |
|
321 |
+ name: PowerShell |
|
322 |
+ - !!models.Tag |
|
323 |
+ category: Language |
|
324 |
+ name: Processing.js |
|
325 |
+ - !!models.Tag |
|
326 |
+ category: Language |
|
327 |
+ name: Prolog |
|
328 |
+ - !!models.Tag |
|
329 |
+ category: Language |
|
330 |
+ name: Visual Prolog |
|
331 |
+ - !!models.Tag |
|
332 |
+ category: Language |
|
333 |
+ name: Python |
|
334 |
+ - !!models.Tag |
|
335 |
+ category: Language |
|
336 |
+ name: QBasic |
|
337 |
+ - !!models.Tag |
|
338 |
+ category: Language |
|
339 |
+ name: QuakeC |
|
340 |
+ - !!models.Tag |
|
341 |
+ category: Language |
|
342 |
+ name: R |
|
343 |
+ - !!models.Tag |
|
344 |
+ category: Language |
|
345 |
+ name: R++ |
|
346 |
+ - !!models.Tag |
|
347 |
+ category: Language |
|
348 |
+ name: REXX |
|
349 |
+ - !!models.Tag |
|
350 |
+ category: Language |
|
351 |
+ name: Ruby |
|
352 |
+ - !!models.Tag |
|
353 |
+ category: Language |
|
354 |
+ name: Rust |
|
355 |
+ - !!models.Tag |
|
356 |
+ category: Language |
|
357 |
+ name: Scala |
|
358 |
+ - !!models.Tag |
|
359 |
+ category: Language |
|
360 |
+ name: Scheme |
|
361 |
+ - !!models.Tag |
|
362 |
+ category: Language |
|
363 |
+ name: Script.NET |
|
364 |
+ - !!models.Tag |
|
365 |
+ category: Language |
|
366 |
+ name: Sed |
|
367 |
+ - !!models.Tag |
|
368 |
+ category: Language |
|
369 |
+ name: Self |
|
370 |
+ - !!models.Tag |
|
371 |
+ category: Language |
|
372 |
+ name: Simula |
|
373 |
+ - !!models.Tag |
|
374 |
+ category: Language |
|
375 |
+ name: Simulink |
|
376 |
+ - !!models.Tag |
|
377 |
+ category: Language |
|
378 |
+ name: Smalltalk |
|
379 |
+ - !!models.Tag |
|
380 |
+ category: Language |
|
381 |
+ name: Small Basic |
|
382 |
+ - !!models.Tag |
|
383 |
+ category: Language |
|
384 |
+ name: Snowball |
|
385 |
+ - !!models.Tag |
|
386 |
+ category: Language |
|
387 |
+ name: Squeak |
|
388 |
+ - !!models.Tag |
|
389 |
+ category: Language |
|
390 |
+ name: Tcl |
|
391 |
+ - !!models.Tag |
|
392 |
+ category: Language |
|
393 |
+ name: TeX |
|
394 |
+ - !!models.Tag |
|
395 |
+ category: Language |
|
396 |
+ name: TEX |
|
397 |
+ - !!models.Tag |
|
398 |
+ category: Language |
|
399 |
+ name: UNITY |
|
400 |
+ - !!models.Tag |
|
401 |
+ category: Language |
|
402 |
+ name: Unix shell |
|
403 |
+ - !!models.Tag |
|
404 |
+ category: Language |
|
405 |
+ name: UnrealScript |
|
406 |
+ - !!models.Tag |
|
407 |
+ category: Language |
|
408 |
+ name: Vala |
|
409 |
+ - !!models.Tag |
|
410 |
+ category: Language |
|
411 |
+ name: VBA |
|
412 |
+ - !!models.Tag |
|
413 |
+ category: Language |
|
414 |
+ name: VBScript |
|
415 |
+ - !!models.Tag |
|
416 |
+ category: Language |
|
417 |
+ name: Verilog |
|
418 |
+ - !!models.Tag |
|
419 |
+ category: Language |
|
420 |
+ name: VHDL |
|
421 |
+ - !!models.Tag |
|
422 |
+ category: Language |
|
423 |
+ name: Visual Basic |
|
424 |
+ - !!models.Tag |
|
425 |
+ category: Language |
|
426 |
+ name: Visual Basic .NET |
|
427 |
+ - !!models.Tag |
|
428 |
+ category: Language |
|
429 |
+ name: Microsoft Visual C++ |
|
430 |
+ - !!models.Tag |
|
431 |
+ category: Language |
|
432 |
+ name: Visual C# |
|
433 |
+ - !!models.Tag |
|
434 |
+ category: Language |
|
435 |
+ name: Visual DataFlex |
|
436 |
+ - !!models.Tag |
|
437 |
+ category: Language |
|
438 |
+ name: Visual DialogScript |
|
439 |
+ - !!models.Tag |
|
440 |
+ category: Language |
|
441 |
+ name: Visual Fortran |
|
442 |
+ - !!models.Tag |
|
443 |
+ category: Language |
|
444 |
+ name: Visual FoxPro |
|
445 |
+ - !!models.Tag |
|
446 |
+ category: Language |
|
447 |
+ name: Visual J++ |
|
448 |
+ - !!models.Tag |
|
449 |
+ category: Language |
|
450 |
+ name: Visual J# |
|
451 |
+ - !!models.Tag |
|
452 |
+ category: Language |
|
453 |
+ name: Windows PowerShell |
|
454 |
+ - !!models.Tag |
|
455 |
+ category: Language |
|
456 |
+ name: XQuery |
|
457 |
+ - !!models.Tag |
|
458 |
+ category: Language |
|
459 |
+ name: XSLT |
|
460 |
+ - !!models.Tag |
|
461 |
+ category: License |
|
462 |
+ name: Apache |
|
463 |
+ - !!models.Tag |
|
464 |
+ category: License |
|
465 |
+ name: BSD |
|
466 |
+ - !!models.Tag |
|
467 |
+ category: License |
|
468 |
+ name: GPL |
|
469 |
+ - !!models.Tag |
|
470 |
+ category: License |
|
471 |
+ name: ISC |
|
472 |
+ - !!models.Tag |
|
473 |
+ category: License |
|
474 |
+ name: LGPL |
|
475 |
+ - !!models.Tag |
|
476 |
+ category: License |
|
477 |
+ name: MIT |
|
478 |
+ - !!models.Tag |
|
479 |
+ category: License |
|
480 |
+ name: MPL v2.0 |
|
481 |
+ - !!models.Tag |
|
482 |
+ category: License |
|
483 |
+ name: Public Domain |
|
484 |
+ - !!models.Tag |
|
485 |
+ category: License |
|
486 |
+ name: Apache |
|
487 |
+ - !!models.Tag |
|
488 |
+ category: License |
|
489 |
+ name: EPL |
|
490 |
+ - !!models.Tag |
|
491 |
+ category: License |
|
492 |
+ name: MPL v1.1 |
--- conf/routes
+++ conf/routes
... | ... | @@ -72,7 +72,7 @@ |
72 | 72 |
GET /:user/:project/post/:id/comment/:commentId/delete controllers.BoardApp.deleteComment(user, project, id:Long, commentId:Long) |
73 | 73 |
|
74 | 74 |
# Tags |
75 |
-GET /tags controllers.TagApp.tags(query: String ?= "") |
|
75 |
+GET /tags controllers.TagApp.tags(query: String ?= "", context: String ?= "", limit: Integer ?= null) |
|
76 | 76 |
GET /:user/:project/tags controllers.ProjectApp.tags(user, project) |
77 | 77 |
POST /:user/:project/tags controllers.ProjectApp.tag(user, project) |
78 | 78 |
POST /:user/:project/tags/:id controllers.ProjectApp.untag(user, project, id: Long) |
+++ docs/technical/tag-typeahead.md
... | ... | @@ -0,0 +1,90 @@ |
1 | +소개 | |
2 | +---- | |
3 | + | |
4 | +HIVE는 태그에 대한 자동완성 API를 제공한다. URL `/tags`로 요청하면 json 포맷으로 된 태그들의 목록을 돌려받는다. | |
5 | + | |
6 | +요청 | |
7 | +---- | |
8 | + | |
9 | +### 메소드 | |
10 | + | |
11 | + GET | |
12 | + | |
13 | +### URL | |
14 | + | |
15 | + /tags | |
16 | + | |
17 | +### 파라메터 | |
18 | + | |
19 | +태그를 요청할 때 쿼리 스트링에 다음의 필드를 포함시킬 수 있다. 쿼리 스트링은 [application/x-www-form-urlencoded](http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type)에 따라 인코딩된다. | |
20 | + | |
21 | +#### query | |
22 | + | |
23 | +태그에 대한 검색어. 서버는 태그의 카테고리나 이름에 이 `query`의 값이 포함된 태그를 반환한다. 대소문자를 구분하지 않는다. | |
24 | + | |
25 | +#### context | |
26 | + | |
27 | +태그를 요청하는 상황에 대한 문맥. 예를 들어 `PROJECT_TAGGING_TYPEAHEAD` 라는 값을 넘겨준 경우, 서버는 현재 상황이 Project Overview 페이지에서 태그를 추가시 자동완성을 위해 태그의 목록을 요청한 것으로 이해하고, 상황에 알맞게(현재 프로젝트에 라이선스 태그가 하나도 없다면 라이선스 태그를 우선한다거나) 태그를 정렬하여 돌려준다. | |
28 | + | |
29 | +#### project_id | |
30 | + | |
31 | +위 `context`에 따라 `project_id` 필드가 필요한 경우가 있다. | |
32 | + | |
33 | +#### limit | |
34 | + | |
35 | +돌려받을 항목의 갯수를 제한한다. 그러나 서버 역시 별도로 넘겨줄 수 있는 항목 갯수의 상한값을 가지고 있을 수 있다. 그러한 경우에는 경우에는 작은 쪽이 선택된다. | |
36 | + | |
37 | +응답 | |
38 | +---- | |
39 | + | |
40 | +응답은 json 형식으로, 문자열의 배열로 반환된다. | |
41 | + | |
42 | +배열의 각 요소는 태그의 카테고리와 이름이 ` - `을 구분자로 하여 조합된 문자열이다. 예를 들어 License 카테고리의 Public Domain이라면 다음과 같다. | |
43 | + | |
44 | + License - Public Domain | |
45 | + | |
46 | +ABNF로 표현하면 다음과 같다. | |
47 | + | |
48 | + tag = tag-category SP "-" SP tag-name | |
49 | + | |
50 | +`-`의 좌우에 SP가 있음에 주의하라. 이것은 보통 엄격하게 검사된다. | |
51 | + | |
52 | +### Content-Range 헤더 | |
53 | + | |
54 | +서버는 항상 자동완성 후보의 목록을 남김없이 모두 둘려주는 것은 아니다. 다음의 경우 일부분만을 돌려줄 수 있다. | |
55 | + | |
56 | +1. 클라이언트가 일부분만을 요청한 경우 (쿼리 스트링의 `limit` 필드를 이용했을 것이다) | |
57 | +2. 서버가 항목의 최대 갯수를 제한하고 있는 경우 | |
58 | + | |
59 | +이러한 경우 서버는 다음과 같은 형식의 Content-Range 헤더를 포함시켜서, 몇 개의 항목 중에서 몇 개의 항목을 돌려주었는지 알려줄 수 있다. (HTTP/1.1의 bytes-range-spec과 차이가 있음에 유의하라) | |
60 | + | |
61 | + Content-Range = items-unit SP number-of-items "/" complete-length | |
62 | + items-unit = "items" | |
63 | + number-of-items = 1*DIGIT | |
64 | + complete-length = 1*DIGIT | |
65 | + SP = <US-ASCII SP, space (32)> | |
66 | + | |
67 | +예를 들어 총 10개 중 8개만을 돌려주었다는 의미의 Content-Range 헤더는 다음과 같다. | |
68 | + | |
69 | + Content-Range: items 8/10 | |
70 | + | |
71 | +`complete-length`는, 서버의 제약이나 클라이언트의 제한 요청이 없었을 경우 돌려주었을 항목의 갯수와 같다. | |
72 | + | |
73 | +주의: 클라이언트의 요청이 Range 요청이 아님에도 Content-Range 헤더를 포함하여 응답하는 것이므로, 응답의 상태 코드는 206 Partial Content 이어서는 안된다. 206으로 응답할 때는 반드시 요청에 Range 헤더가 포함되어 있어야 하기(MUST) 때문이다. | |
74 | + | |
75 | +예외처리 | |
76 | +-------- | |
77 | + | |
78 | +* 오로지 json으로만 응답이 가능하기 때문에, `application/json`을 받아들일 수 없는 요청이라면 406 Not Acceptable로 응답한다. | |
79 | +* 필요한 파라메터가 없거나, 잘못된 파라메터가 주어진 경우에는 400 Bad Request로 응답한다. | |
80 | + | |
81 | +요청과 응답의 예 | |
82 | +---------------- | |
83 | + | |
84 | +요청 | |
85 | + | |
86 | + GET /tags?context=PROJECT_TAGGING_TYPEAHEAD&limit=8&project_id=1&query=a | |
87 | + | |
88 | +응답 | |
89 | + | |
90 | + ["License - Public Domain","Language - @Formula","Language - A# (Axiom)","Language - A# .NET","Language - A+","Language - A++","Language - A-0 System","Language - ABAP"] |
--- public/javascripts/common/hive.ui.Typeahead.js
+++ public/javascripts/common/hive.ui.Typeahead.js
... | ... | @@ -30,6 +30,7 @@ |
30 | 30 |
function _initVar(htOptions){ |
31 | 31 |
htVar.sActionURL = htOptions.sActionURL || "/users"; |
32 | 32 |
htVar.rxContentRange = /items\s+([0-9]+)\/([0-9]+)/; |
33 |
+ htVar.htData = htOptions.htData; |
|
33 | 34 |
} |
34 | 35 |
|
35 | 36 |
/** |
... | ... | @@ -39,8 +40,11 @@ |
39 | 40 |
*/ |
40 | 41 |
function _initElement(sQuery){ |
41 | 42 |
htElement.welInput = $(sQuery); |
42 |
- htElement.welInput.typeahead(); |
|
43 |
- htElement.welInput.data("typeahead").source = _onTypeAhead; |
|
43 |
+ htElement.welInput.typeahead({ |
|
44 |
+ source: _onTypeAhead, |
|
45 |
+ minLength: 0, |
|
46 |
+ items: htVar.htData.limit || 8 |
|
47 |
+ }); |
|
44 | 48 |
} |
45 | 49 |
|
46 | 50 |
/** |
... | ... | @@ -56,10 +60,11 @@ |
56 | 60 |
if (sQuery.match(htVar.sLastQuery) && htVar.bIsLastRangeEntire) { |
57 | 61 |
fProcess(htVar.htCachedUsers); |
58 | 62 |
} else { |
63 |
+ htVar.htData.query = sQuery; |
|
59 | 64 |
$hive.sendForm({ |
60 | 65 |
"sURL" : htVar.sActionURL, |
61 | 66 |
"htOptForm" : {"method":"get"}, |
62 |
- "htData" : {"query": sQuery}, |
|
67 |
+ "htData" : htVar.htData, |
|
63 | 68 |
"sDataType" : "json", |
64 | 69 |
"fOnLoad" : function(oData, oStatus, oXHR){ |
65 | 70 |
var sContentRange = oXHR.getResponseHeader('Content-Range'); |
+++ public/javascripts/lib/bootstrap-better-typeahead.js
... | ... | @@ -0,0 +1,136 @@ |
1 | +/* ============================================================= | |
2 | + * bootstrap-better-typeahead.js v1.0.0 by Philipp Nolte | |
3 | + * https://github.com/ptnplanet/Bootstrap-Better-Typeahead | |
4 | + * ============================================================= | |
5 | + * This plugin makes use of twitter bootstrap typeahead | |
6 | + * http://twitter.github.com/bootstrap/javascript.html#typeahead | |
7 | + * | |
8 | + * Bootstrap is licensed under the Apache License, Version 2.0 | |
9 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + * ============================================================ */ | |
11 | + | |
12 | +// ************************************************** | |
13 | +// Hive modifications by Yi EungJun | |
14 | +// http://github.github.com/nforge/hive/ | |
15 | +// | |
16 | +// Modifications are tagged with "hive" | |
17 | +// ************************************************** | |
18 | + | |
19 | +!function($) { | |
20 | + | |
21 | + "use strict"; | |
22 | + | |
23 | + /** | |
24 | + * The better typeahead plugin will extend the bootstrap typeahead plugin and provide the abbility to set the | |
25 | + * maxLength option to zero. The tab keyup event handler had to be moved to the keydown event handler, so that | |
26 | + * the full list of available items is shown on tab-focus and the original behaviour is preserved as best as | |
27 | + * possible. | |
28 | + * | |
29 | + * @type {object} | |
30 | + */ | |
31 | + var BetterTypeahead = { | |
32 | + | |
33 | + lookup: function(event) { | |
34 | + var items; | |
35 | + | |
36 | + // Now supports empty queries (eg. with a length of 0). | |
37 | + this.query = this.$element.val() || ''; | |
38 | + | |
39 | + if (this.query.length < this.options.minLength) { | |
40 | + return this.shown ? this.hide() : this; | |
41 | + } | |
42 | + | |
43 | + items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source; | |
44 | + | |
45 | + return items ? this.process(items) : this; | |
46 | + } | |
47 | + | |
48 | + , process: function (items) { | |
49 | + var that = this; | |
50 | + | |
51 | + items = $.grep(items, function (item) { | |
52 | + return that.matcher(item); | |
53 | + }); | |
54 | + | |
55 | + items = this.sorter(items); | |
56 | + | |
57 | + if (!items.length) { | |
58 | + return this.shown ? this.hide() : this; | |
59 | + } | |
60 | + | |
61 | + // hive: If-clause to make this work only if query's length is more | |
62 | + // than 0, has been removed from the original version. | |
63 | + items = items.slice(0, this.options.items); | |
64 | + | |
65 | + return this.render(items).show(); | |
66 | + } | |
67 | + | |
68 | + , render: function (items) { | |
69 | + var that = this | |
70 | + | |
71 | + items = $(items).map(function (i, item) { | |
72 | + i = $(that.options.item).attr('data-value', item); | |
73 | + i.find('a').html(that.highlighter(item)); | |
74 | + return i[0]; | |
75 | + }); | |
76 | + | |
77 | + if (this.query.length > 0) { | |
78 | + items.first().addClass('active'); | |
79 | + } | |
80 | + | |
81 | + this.$menu.html(items); | |
82 | + return this; | |
83 | + } | |
84 | + | |
85 | + , keydown: function (e) { | |
86 | + this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]); | |
87 | + | |
88 | + // Added tab handler. Tabbing out of the input (thus blurring). | |
89 | + if (e.keyCode === 9) { // tab | |
90 | + if (!this.shown) return; | |
91 | + this.select(); | |
92 | + } else { | |
93 | + this.move(e); | |
94 | + } | |
95 | + } | |
96 | + | |
97 | + , keyup: function (e) { | |
98 | + switch(e.keyCode) { | |
99 | + case 40: // down arrow | |
100 | + case 38: // up arrow | |
101 | + case 16: // shift | |
102 | + case 17: // ctrl | |
103 | + case 18: // alt | |
104 | + break; | |
105 | + | |
106 | + // Moved tab handler to keydown. | |
107 | + case 13: // enter | |
108 | + if (!this.shown) return; | |
109 | + this.select(); | |
110 | + break; | |
111 | + | |
112 | + case 27: // escape; | |
113 | + if (!this.shown) return; | |
114 | + this.hide(); | |
115 | + break; | |
116 | + | |
117 | + default: | |
118 | + this.lookup(); | |
119 | + } | |
120 | + | |
121 | + e.stopPropagation(); | |
122 | + e.preventDefault(); | |
123 | + } | |
124 | + | |
125 | + , focus: function(e) { | |
126 | + this.focused = true; | |
127 | + | |
128 | + if (!this.mousedover) { | |
129 | + this.lookup(e); | |
130 | + } | |
131 | + } | |
132 | + }; | |
133 | + | |
134 | + $.extend($.fn.typeahead.Constructor.prototype, BetterTypeahead); | |
135 | + | |
136 | +}(window.jQuery); |
--- public/javascripts/service/hive.project.Home.js
+++ public/javascripts/service/hive.project.Home.js
... | ... | @@ -16,15 +16,31 @@ |
16 | 16 |
var htElement = {}; |
17 | 17 |
|
18 | 18 |
function _init(htOptions){ |
19 |
+ var htOpt = htOptions || {}; |
|
20 |
+ _initVar(htOpt); |
|
19 | 21 |
_initElement(htOptions); |
20 | 22 |
_attachEvent(); |
23 |
+ _initTags(); |
|
21 | 24 |
} |
22 |
- |
|
25 |
+ |
|
26 |
+ function _initVar(htOptions){ |
|
27 |
+ htVar.sURLProjectTags = htOptions.sURLProjectTags; |
|
28 |
+ htVar.sURLTags = htOptions.sURLTags; |
|
29 |
+ htVar.nProjectId = htOptions.nProjectId; |
|
30 |
+ } |
|
31 |
+ |
|
23 | 32 |
/** |
24 | 33 |
* initialize element |
25 | 34 |
*/ |
26 | 35 |
function _initElement(htOptions){ |
27 | 36 |
htElement.welRepoURL = $("#repositoryURL"); |
37 |
+ |
|
38 |
+ // tags |
|
39 |
+ htElement.welInputAddTag = $('input[name="newTag"]'); |
|
40 |
+ htElement.welTags = $('#tags'); |
|
41 |
+ htElement.welBtnAddTag = $('#addTag'); |
|
42 |
+ htElement.welTagEditorToggle = $('#tag-editor-toggle'); |
|
43 |
+ htElement.waTag = $(); |
|
28 | 44 |
} |
29 | 45 |
|
30 | 46 |
/** |
... | ... | @@ -32,12 +48,203 @@ |
32 | 48 |
*/ |
33 | 49 |
function _attachEvent(){ |
34 | 50 |
htElement.welRepoURL.click(_onClickRepoURL); |
51 |
+ htElement.welInputAddTag.keypress(_onKeyPressNewTag); |
|
52 |
+ htElement.welBtnAddTag.click(_submitTag); |
|
53 |
+ htElement.welTagEditorToggle.on('click', function() { |
|
54 |
+ if ($(this).hasClass('active')) { |
|
55 |
+ // Now inactive |
|
56 |
+ _hideTagEditor(); |
|
57 |
+ } else { |
|
58 |
+ // Now active |
|
59 |
+ _showTagEditor(); |
|
60 |
+ } |
|
61 |
+ }); |
|
62 |
+ new hive.ui.Typeahead(htElement.welInputAddTag, { |
|
63 |
+ "sActionURL": htVar.sURLTags, |
|
64 |
+ "htData": { |
|
65 |
+ "context": "PROJECT_TAGGING_TYPEAHEAD", |
|
66 |
+ "project_id": htVar.nProjectId, |
|
67 |
+ "limit": 8 |
|
68 |
+ } |
|
69 |
+ }); |
|
35 | 70 |
} |
36 |
- |
|
71 |
+ |
|
37 | 72 |
function _onClickRepoURL(){ |
38 | 73 |
htElement.welRepoURL.select(); |
39 | 74 |
} |
40 |
- |
|
75 |
+ |
|
76 |
+ /** |
|
77 |
+ * Add a tag, which user types in htElement.welInputAddTag, into #tags div. |
|
78 |
+ * |
|
79 |
+ * @param {Object} oEvent |
|
80 |
+ */ |
|
81 |
+ function _onKeyPressNewTag(oEvent) { |
|
82 |
+ if (oEvent.keyCode == 13) { |
|
83 |
+ _submitTag(); |
|
84 |
+ htElement.welInputAddTag.val(""); |
|
85 |
+ return false; |
|
86 |
+ } |
|
87 |
+ } |
|
88 |
+ |
|
89 |
+ function _parseTag(sTag) { |
|
90 |
+ var sSeparator = ' - '; |
|
91 |
+ var aPart = |
|
92 |
+ jQuery.map(sTag.split(sSeparator), function(s) { return s.trim(); }); |
|
93 |
+ var htTag; |
|
94 |
+ |
|
95 |
+ if (aPart.length > 2) { |
|
96 |
+ aPart = [aPart.shift(), aPart.join(sSeparator)]; |
|
97 |
+ } |
|
98 |
+ |
|
99 |
+ if (aPart.length > 1) { |
|
100 |
+ htTag = {"category": aPart[0], "name": aPart[1]}; |
|
101 |
+ } else if (aPart.length == 1) { |
|
102 |
+ htTag = {"category": "Tag", "name": aPart[0]}; |
|
103 |
+ } else { |
|
104 |
+ return null; |
|
105 |
+ } |
|
106 |
+ |
|
107 |
+ return htTag; |
|
108 |
+ } |
|
109 |
+ |
|
110 |
+ /** |
|
111 |
+ * Submit new tag to add that. |
|
112 |
+ */ |
|
113 |
+ function _submitTag () { |
|
114 |
+ var htTag = _parseTag(htElement.welInputAddTag.val()); |
|
115 |
+ |
|
116 |
+ if (htTag == null) { |
|
117 |
+ return; |
|
118 |
+ } |
|
119 |
+ |
|
120 |
+ $hive.sendForm({ |
|
121 |
+ "sURL" : htVar.sURLProjectTags, |
|
122 |
+ "htData" : htTag, |
|
123 |
+ "fOnLoad": _appendTags |
|
124 |
+ }); |
|
125 |
+ } |
|
126 |
+ |
|
127 |
+ /** |
|
128 |
+ * Get list of tags from the server and show them in #tags div. |
|
129 |
+ */ |
|
130 |
+ function _initTags() { |
|
131 |
+ $hive.sendForm({ |
|
132 |
+ "sURL" : htVar.sURLProjectTags, |
|
133 |
+ "htOptForm": {"method":"get"}, |
|
134 |
+ "fOnLoad" : function(data) { |
|
135 |
+ _appendTags(data); |
|
136 |
+ _hideTagEditor(); |
|
137 |
+ } |
|
138 |
+ }); |
|
139 |
+ } |
|
140 |
+ |
|
141 |
+ /** |
|
142 |
+ * Make a tag element by given instance id and name. |
|
143 |
+ * |
|
144 |
+ * @param {String} sInstanceId |
|
145 |
+ * @param {String} sName |
|
146 |
+ */ |
|
147 |
+ function _createTag(sInstanceId, sName) { |
|
148 |
+ // If someone clicks a delete button, remove the tag which contains |
|
149 |
+ // the button, and also hide its category in .project-info div if |
|
150 |
+ // the category becomes to have no tag. |
|
151 |
+ var fOnClickDelete = function() { |
|
152 |
+ $hive.sendForm({ |
|
153 |
+ "sURL" : htVar.sURLProjectTags + '/' + sInstanceId, |
|
154 |
+ "htData" : {"_method":"DELETE"}, |
|
155 |
+ "fOnLoad": function(){ |
|
156 |
+ var welCategory = welTag.parent(); |
|
157 |
+ welTag.remove(); |
|
158 |
+ if (welCategory.children('span').length == 0) { |
|
159 |
+ welCategory.remove(); |
|
160 |
+ } |
|
161 |
+ } |
|
162 |
+ }); |
|
163 |
+ }; |
|
164 |
+ |
|
165 |
+ var welDeleteButton = $('<a>') |
|
166 |
+ .attr('href', 'javascript:void(0)') |
|
167 |
+ .text(' x') |
|
168 |
+ .click(fOnClickDelete); |
|
169 |
+ |
|
170 |
+ var welTag = $('<span>') |
|
171 |
+ .text(sName) |
|
172 |
+ .addClass('label') |
|
173 |
+ .append(welDeleteButton); |
|
174 |
+ |
|
175 |
+ welTag.setRemovability = function(bFlag) { |
|
176 |
+ if (bFlag === true) { |
|
177 |
+ welTag.addClass('label'); |
|
178 |
+ welDeleteButton.show(); |
|
179 |
+ } else { |
|
180 |
+ welTag.removeClass('label'); |
|
181 |
+ welDeleteButton.hide(); |
|
182 |
+ } |
|
183 |
+ } |
|
184 |
+ |
|
185 |
+ htElement.waTag.push(welTag); |
|
186 |
+ |
|
187 |
+ return welTag; |
|
188 |
+ } |
|
189 |
+ |
|
190 |
+ /** |
|
191 |
+ * Append the given tags on #tags div to show them. |
|
192 |
+ * |
|
193 |
+ * @param {Object} htTags |
|
194 |
+ */ |
|
195 |
+ function _appendTags(htTags) { |
|
196 |
+ for(var sInstanceId in htTags) { |
|
197 |
+ var waChildren, newCategory; |
|
198 |
+ var htTag = _parseTag(htTags[sInstanceId]); |
|
199 |
+ |
|
200 |
+ waChildren = |
|
201 |
+ htElement.welTags.children("[category=" + htTag.category + "]"); |
|
202 |
+ |
|
203 |
+ if (waChildren.length > 0) { |
|
204 |
+ waChildren.append(_createTag(sInstanceId, htTag.name)); |
|
205 |
+ } else { |
|
206 |
+ newCategory = $('<li>') |
|
207 |
+ .addClass('info') |
|
208 |
+ .attr('category', htTag.category) |
|
209 |
+ .append($('<strong>').text(htTag.category + ' : ')) |
|
210 |
+ .append(_createTag(sInstanceId, htTag.name)); |
|
211 |
+ htElement.welTags.append(newCategory); |
|
212 |
+ } |
|
213 |
+ } |
|
214 |
+ } |
|
215 |
+ |
|
216 |
+ /** |
|
217 |
+ * Show all delete buttons for all tags if bFlag is true, and hide if |
|
218 |
+ * bFlag is false. |
|
219 |
+ * |
|
220 |
+ * @param {Boolean} bFlag |
|
221 |
+ */ |
|
222 |
+ function _setTagsRemovability(bFlag) { |
|
223 |
+ jQuery.map(htElement.waTag, function(tag) { tag.setRemovability(bFlag); }); |
|
224 |
+ } |
|
225 |
+ |
|
226 |
+ /** |
|
227 |
+ * Make .project-info div editable. |
|
228 |
+ * |
|
229 |
+ * @param {Boolean} bFlag |
|
230 |
+ */ |
|
231 |
+ function _hideTagEditor() { |
|
232 |
+ _setTagsRemovability(false); |
|
233 |
+ htElement.welInputAddTag.addClass('hidden'); |
|
234 |
+ htElement.welBtnAddTag.addClass('hidden'); |
|
235 |
+ } |
|
236 |
+ |
|
237 |
+ /** |
|
238 |
+ * Make .project-info div uneditable. |
|
239 |
+ * |
|
240 |
+ * @param {Boolean} bFlag |
|
241 |
+ */ |
|
242 |
+ function _showTagEditor() { |
|
243 |
+ _setTagsRemovability(true); |
|
244 |
+ htElement.welInputAddTag.removeClass('hidden'); |
|
245 |
+ htElement.welBtnAddTag.removeClass('hidden'); |
|
246 |
+ } |
|
247 |
+ |
|
41 | 248 |
_init(htOptions || {}); |
42 | 249 |
}; |
43 | 250 |
|
--- public/javascripts/service/hive.project.Setting.js
+++ public/javascripts/service/hive.project.Setting.js
... | ... | @@ -23,7 +23,6 @@ |
23 | 23 |
_initVar(htOpt); |
24 | 24 |
_initElement(htOpt); |
25 | 25 |
_attachEvent(); |
26 |
- _updateTags(); |
|
27 | 26 |
|
28 | 27 |
htVar.waPopOvers.popover(); |
29 | 28 |
} |
... | ... | @@ -35,8 +34,6 @@ |
35 | 34 |
function _initVar(htOptions){ |
36 | 35 |
htVar.rxLogoExt = /\.(gif|bmp|jpg|jpeg|png)$/i; |
37 | 36 |
htVar.rxPrjName = /^[a-zA-Z0-9_][-a-zA-Z0-9_]+[^-]$/; |
38 |
- htVar.sURLProjectTags = htOptions.sURLProjectTags; |
|
39 |
- htVar.sURLTags = htOptions.sURLTags; |
|
40 | 37 |
} |
41 | 38 |
|
42 | 39 |
/** |
... | ... | @@ -60,27 +57,15 @@ |
60 | 57 |
|
61 | 58 |
// popovers |
62 | 59 |
htVar.waPopOvers = $([$("#project_name"), $("#share_option_explanation"), $("#terms")]); |
63 |
- |
|
64 |
- // tags |
|
65 |
- htElement.welInputAddTag = $('input[name="newTag"]'); |
|
66 |
- htElement.welTags = $('#tags'); |
|
67 |
- htElement.welBtnAddTag = $('#addTag'); |
|
68 |
- |
|
69 |
- htVar.oTagInput = new hive.ui.Typeahead(htElement.welInputAddTag, { |
|
70 |
- "sActionURL": htVar.sURLTags |
|
71 |
- }); |
|
72 | 60 |
} |
73 | 61 |
|
74 |
- /** |
|
62 |
+ /** |
|
75 | 63 |
* attach event handlers |
76 | 64 |
*/ |
77 | 65 |
function _attachEvent(){ |
78 | 66 |
htElement.welInputLogo.change(_onChangeLogoPath); |
79 | 67 |
htElement.welBtnDeletePrj.click(_onClickBtnDeletePrj); |
80 | 68 |
htElement.welBtnSave.click(_onClickBtnSave); |
81 |
- htElement.welInputAddTag.keypress(_onKeyPressNewTag); |
|
82 |
-// .typeahead().data('typeahead').source = _tagTypeaheadSource; |
|
83 |
- htElement.welBtnAddTag.click(_submitTag); |
|
84 | 69 |
} |
85 | 70 |
|
86 | 71 |
/** |
... | ... | @@ -125,76 +110,6 @@ |
125 | 110 |
return true; |
126 | 111 |
} |
127 | 112 |
|
128 |
- /** |
|
129 |
- * Submit new tag to add that. |
|
130 |
- */ |
|
131 |
- function _submitTag () { |
|
132 |
- $hive.sendForm({ |
|
133 |
- "sURL" : htVar.sURLProjectTags, |
|
134 |
- "htData" : {"name": htElement.welInputAddTag.val()}, |
|
135 |
- "fOnLoad": _appendTags |
|
136 |
- }); |
|
137 |
- } |
|
138 |
- |
|
139 |
- /** |
|
140 |
- * Add a tag, which user types in htElement.welInputAddTag, into #tags div. |
|
141 |
- * |
|
142 |
- * @param {Object} oEvent |
|
143 |
- */ |
|
144 |
- function _onKeyPressNewTag(oEvent) { |
|
145 |
- if (oEvent.keyCode == 13) { |
|
146 |
- _submitTag(); |
|
147 |
- htElement.welInputAddTag.val(""); |
|
148 |
- return false; |
|
149 |
- } |
|
150 |
- } |
|
151 |
- |
|
152 |
- /** |
|
153 |
- * Get list of tags from the server and show them in #tags div. |
|
154 |
- */ |
|
155 |
- function _updateTags() { |
|
156 |
- $hive.sendForm({ |
|
157 |
- "sURL" : htVar.sURLProjectTags, |
|
158 |
- "htOptForm": {"method":"get"}, |
|
159 |
- "fOnLoad" : _appendTags |
|
160 |
- }); |
|
161 |
- } |
|
162 |
- |
|
163 |
- /** |
|
164 |
- * Make a tag element by given id and name. |
|
165 |
- |
|
166 |
- * @param {String} sId |
|
167 |
- * @param {String} sName |
|
168 |
- */ |
|
169 |
- function _createTag(sId, sName) { |
|
170 |
- var fOnClickDelete = function() { |
|
171 |
- $hive.sendForm({ |
|
172 |
- "sURL" : htVar.sURLProjectTags + '/' + sId, |
|
173 |
- "htData" : {"_method":"DELETE"}, |
|
174 |
- "fOnLoad": function(){ |
|
175 |
- welTag.remove(); |
|
176 |
- } |
|
177 |
- }); |
|
178 |
- }; |
|
179 |
- |
|
180 |
- var welTag = $('<span class="label label-info">' + sName + " </span>") |
|
181 |
- .append($('<a href="javascript:void(0)">x</a>') |
|
182 |
- .click(fOnClickDelete)); |
|
183 |
- |
|
184 |
- return welTag; |
|
185 |
- } |
|
186 |
- |
|
187 |
- /** |
|
188 |
- * Append the given tags on #tags div to show them. |
|
189 |
- * |
|
190 |
- * @param {Object} htTags |
|
191 |
- */ |
|
192 |
- function _appendTags(htTags) { |
|
193 |
- for(var sId in htTags) { |
|
194 |
- htElement.welTags.append(_createTag(sId, htTags[sId])); |
|
195 |
- } |
|
196 |
- } |
|
197 |
- |
|
198 | 113 |
_init(htOptions); |
199 | 114 |
}; |
200 | 115 |
|
--- test/controllers/ProjectAppTest.java
+++ test/controllers/ProjectAppTest.java
... | ... | @@ -31,7 +31,8 @@ |
31 | 31 |
public void run() { |
32 | 32 |
//Given |
33 | 33 |
Map<String,String> data = new HashMap<String,String>(); |
34 |
- data.put("name", "foo"); |
|
34 |
+ data.put("category", "OS"); |
|
35 |
+ data.put("name", "linux"); |
|
35 | 36 |
User admin = User.findByLoginId("admin"); |
36 | 37 |
|
37 | 38 |
//When |
... | ... | @@ -44,13 +45,13 @@ |
44 | 45 |
); |
45 | 46 |
|
46 | 47 |
//Then |
47 |
- assertThat(status(result)).isEqualTo(OK); |
|
48 |
+ assertThat(status(result)).isEqualTo(CREATED); |
|
48 | 49 |
Iterator<Map.Entry<String, JsonNode>> fields = Json.parse(contentAsString(result)).getFields(); |
49 | 50 |
Map.Entry<String, JsonNode> field = fields.next(); |
50 | 51 |
Tag expected = new Tag(); |
51 | 52 |
expected.id = Long.valueOf(field.getKey()); |
52 | 53 |
expected.name = field.getValue().asText(); |
53 |
- assertThat(expected.name).isEqualTo("foo"); |
|
54 |
+ assertThat(expected.name).isEqualTo("OS - linux"); |
|
54 | 55 |
assertThat(Project.findByNameAndOwner("hobi", "nForge4java").tags.contains(expected)).isTrue(); |
55 | 56 |
} |
56 | 57 |
}); |
... | ... | @@ -63,14 +64,13 @@ |
63 | 64 |
//Given |
64 | 65 |
Project project = Project.findByNameAndOwner("hobi", "nForge4java"); |
65 | 66 |
|
66 |
- Tag tag1 = new Tag(); |
|
67 |
- tag1.name = "foo"; |
|
67 |
+ Tag tag1 = new Tag("OS", "linux"); |
|
68 | 68 |
tag1.save(); |
69 | 69 |
project.tags.add(tag1); |
70 | 70 |
project.update(); |
71 | 71 |
|
72 |
- Tag tag2 = new Tag(); |
|
73 |
- tag2.name = "bar"; |
|
72 |
+ // If null is given as the first parameter, "Tag" is chosen as the category. |
|
73 |
+ Tag tag2 = new Tag(null, "foo"); |
|
74 | 74 |
tag2.save(); |
75 | 75 |
project.tags.add(tag2); |
76 | 76 |
project.update(); |
... | ... | @@ -87,8 +87,8 @@ |
87 | 87 |
JsonNode json = Json.parse(contentAsString(result)); |
88 | 88 |
assertThat(json.has(tag1.id.toString())).isTrue(); |
89 | 89 |
assertThat(json.has(tag2.id.toString())).isTrue(); |
90 |
- assertThat(json.get(tag1.id.toString()).asText()).isEqualTo("foo"); |
|
91 |
- assertThat(json.get(tag2.id.toString()).asText()).isEqualTo("bar"); |
|
90 |
+ assertThat(json.get(tag1.id.toString()).asText()).isEqualTo("OS - linux"); |
|
91 |
+ assertThat(json.get(tag2.id.toString()).asText()).isEqualTo("Tag - foo"); |
|
92 | 92 |
} |
93 | 93 |
}); |
94 | 94 |
} |
... | ... | @@ -100,8 +100,7 @@ |
100 | 100 |
//Given |
101 | 101 |
Project project = Project.findByNameAndOwner("hobi", "nForge4java"); |
102 | 102 |
|
103 |
- Tag tag1 = new Tag(); |
|
104 |
- tag1.name = "foo"; |
|
103 |
+ Tag tag1 = new Tag("OS", "linux"); |
|
105 | 104 |
tag1.save(); |
106 | 105 |
project.tags.add(tag1); |
107 | 106 |
project.update(); |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?