
Merge branch 'fix-shortcutkeys-140313' of laziel/yobi
from pull request 711
@c559b3c4b298a9d641d8dc8aef72c118ec64841e
--- app/assets/stylesheets/less/_page.less
+++ app/assets/stylesheets/less/_page.less
... | ... | @@ -4431,9 +4431,11 @@ |
4431 | 4431 |
.keymap-help { |
4432 | 4432 |
padding:20px; |
4433 | 4433 |
line-height:30px; |
4434 |
+ white-space:nowrap; |
|
4434 | 4435 |
|
4435 |
- .nbtn { |
|
4436 |
+ .ybtn { |
|
4436 | 4437 |
min-width:20px; |
4438 |
+ margin-right:3px; |
|
4437 | 4439 |
} |
4438 | 4440 |
.actrow { |
4439 | 4441 |
text-align:center; |
--- app/views/board/list.scala.html
+++ app/views/board/list.scala.html
... | ... | @@ -89,12 +89,6 @@ |
89 | 89 |
|
90 | 90 |
yobi.ShortcutKey.setKeymapLink({ |
91 | 91 |
"N": "@routes.BoardApp.newPostForm(project.owner, project.name)" |
92 |
- @if(page.getPageIndex > 0){ |
|
93 |
- ,"A": "@getPageListUrl(page.getPageIndex - 1)" |
|
94 |
- } |
|
95 |
- @if(page.getTotalPageCount > 1 && (page.getPageIndex + 1 != page.getTotalPageCount)){ |
|
96 |
- ,"S": "@getPageListUrl(page.getPageIndex + 1)" |
|
97 |
- } |
|
98 | 92 |
}); |
99 | 93 |
}); |
100 | 94 |
</script> |
--- app/views/board/view.scala.html
+++ app/views/board/view.scala.html
... | ... | @@ -144,7 +144,7 @@ |
144 | 144 |
// yobi.ShortcutKey |
145 | 145 |
yobi.ShortcutKey.setKeymapLink({ |
146 | 146 |
"N": "@routes.BoardApp.newPostForm(project.owner, project.name)", |
147 |
- "L": "@routes.BoardApp.posts(project.owner, project.name)" |
|
147 |
+ "L": "@urlToPostings" |
|
148 | 148 |
@if(isAllowed(UserApp.currentUser(), post.asResource(), Operation.UPDATE)){ |
149 | 149 |
,"E": "@routes.BoardApp.editPostForm(project.owner, project.name, post.getNumber)" |
150 | 150 |
} |
--- app/views/help/keymap.scala.html
+++ app/views/help/keymap.scala.html
... | ... | @@ -1,5 +1,7 @@ |
1 | 1 |
@(section:String, project:Project) |
2 | 2 |
|
3 |
+@ctrl = @{if(request.headers.get("User-Agent")(0).contains("Macintosh")){"⌘"}else{"CTRL"}} |
|
4 |
+ |
|
3 | 5 |
<div class="pull-right" style="padding:10px 0;"> |
4 | 6 |
<a href="#helpKeys" data-toggle="modal" class="ybtn ybtn-inverse ybtn-mini"> |
5 | 7 |
<i class="yobicon-info-sign"></i> @Messages("title.keymap") |
... | ... | @@ -7,7 +9,7 @@ |
7 | 9 |
|
8 | 10 |
<div id="helpKeys" class="modal hide fade keymap-help" tabindex="-1" role="dialog"> |
9 | 11 |
<div class="row-fluid"> |
10 |
- <div class="span4"> |
|
12 |
+ <div class="span3"> |
|
11 | 13 |
<h5>@Messages("project.projects")</h5> |
12 | 14 |
<span class="ybtn ybtn-small">H</span> |
13 | 15 |
<span class="help-inline">@Messages("menu.home")</span><br> |
... | ... | @@ -69,20 +71,20 @@ |
69 | 71 |
} |
70 | 72 |
|
71 | 73 |
@if(section == "issueList"){ |
72 |
- <span class="ybtn ybtn-small">CTRL</span>+ <span class="ybtn ybtn-small">A</span> |
|
74 |
+ <span class="ybtn ybtn-small">@ctrl</span>+ <span class="ybtn ybtn-small">A</span> |
|
73 | 75 |
<span class="help-inline">@Messages("button.selectAll")</span><br> |
74 | 76 |
} |
75 | 77 |
</div> |
76 | 78 |
|
77 |
- <div class="span4"> |
|
79 |
+ <div class="span5"> |
|
78 | 80 |
<h5>@Messages("site")</h5> |
79 | 81 |
<span class="ybtn ybtn-small">P</span> |
80 | 82 |
<span class="help-inline">@Messages("userinfo.profile")</span><br> |
81 | 83 |
|
82 |
- <span class="ybtn ybtn-small">ALT</span>+ <span class="ybtn ybtn-small">S</span> |
|
84 |
+ <span class="ybtn ybtn-small">ALT</span> + <span class="ybtn ybtn-small">S</span> |
|
83 | 85 |
<span class="help-inline">@Messages("site.search")</span><br> |
84 | 86 |
|
85 |
- <span class="ybtn ybtn-small">CTRL</span>+ <span class="ybtn ybtn-small">ENTER</span> |
|
87 |
+ <span class="ybtn ybtn-small">@ctrl</span> + <span class="ybtn ybtn-small">ENTER</span> |
|
86 | 88 |
<span class="help-inline">@Messages("button.submitForm")</span><br> |
87 | 89 |
</div> |
88 | 90 |
</div> |
--- app/views/issue/partial_search.scala.html
+++ app/views/issue/partial_search.scala.html
... | ... | @@ -241,12 +241,6 @@ |
241 | 241 |
// ShortcutKey |
242 | 242 |
yobi.ShortcutKey.setKeymapLink({ |
243 | 243 |
"N": "@routes.IssueApp.newIssueForm(project.owner, project.name)" |
244 |
- @if(currentPage.getPageIndex > 0){ |
|
245 |
- ,"A": "@getPageListUrl(currentPage.getPageIndex - 1)" |
|
246 |
- } |
|
247 |
- @if(currentPage.getTotalPageCount > 1 && (currentPage.getPageIndex + 1 != currentPage.getTotalPageCount)){ |
|
248 |
- ,"S": "@getPageListUrl(currentPage.getPageIndex + 1)" |
|
249 |
- } |
|
250 | 244 |
}); |
251 | 245 |
}); |
252 | 246 |
</script> |
--- app/views/issue/view.scala.html
+++ app/views/issue/view.scala.html
... | ... | @@ -309,13 +309,16 @@ |
309 | 309 |
"welMilestone" : $("#milestone"), |
310 | 310 |
"welAssignee" : $("#assignee"), |
311 | 311 |
"welIssueUpdateForm": $("#issueUpdateForm"), |
312 |
- "sIssueCheckBoxesSelector": "[type=checkbox][name=checked-issue]" |
|
312 |
+ "sIssueCheckBoxesSelector": "[type=checkbox][name=checked-issue]", |
|
313 |
+ "sNextState" : "@issue.nextState().toString.toLowerCase", |
|
314 |
+ "sNextStateUrl" : "@routes.IssueApp.nextState(project.owner, project.name, issue.getNumber)", |
|
315 |
+ "sCommentWithStateUrl": "@routes.IssueApp.newCommentWithState(project.owner, project.name, issue.getNumber)" |
|
313 | 316 |
}); |
314 | 317 |
|
315 | 318 |
// yobi.ShortcutKey |
316 | 319 |
yobi.ShortcutKey.setKeymapLink({ |
317 | 320 |
"N": "@routes.IssueApp.newIssueForm(project.owner, project.name)", |
318 |
- "L": "@routes.IssueApp.issues(project.owner, project.name,"open")" |
|
321 |
+ "L": "@urlToIssues" |
|
319 | 322 |
@if(isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) { |
320 | 323 |
,"E": "@routes.IssueApp.editIssueForm(project.owner, project.name, issue.getNumber)" |
321 | 324 |
} |
... | ... | @@ -324,39 +327,6 @@ |
324 | 327 |
yobi.Mention({ |
325 | 328 |
target:'comment-editor', |
326 | 329 |
url : "@Html(routes.ProjectApp.mentionList(project.owner, project.name, issue.getNumber, issue.asResource().getType.resource()).toString())" |
327 |
- }); |
|
328 |
- }); |
|
329 |
-</script> |
|
330 |
- |
|
331 |
-<script> |
|
332 |
- //add "comment & close" like button at comment form |
|
333 |
- $(function(){ |
|
334 |
- var welEditor = $("#comment-editor"); |
|
335 |
- var welDynamicCommentBtn = $("#dynamic-comment-btn"); |
|
336 |
- var welCommentForm = $("#comment-form" ); |
|
337 |
- var welWithStateTransition = $("<input type='hidden' name='withStateTransition'>"); |
|
338 |
- |
|
339 |
- var sNextState = "@Messages("button.nextState."+issue.nextState().toString.toLowerCase)"; |
|
340 |
- var sCommentAndNextState = "@Html(Messages("button.commentAndNextState."+issue.nextState().toString.toLowerCase))"; |
|
341 |
- welCommentForm.prepend(welWithStateTransition); |
|
342 |
- welDynamicCommentBtn.removeClass('hidden'); |
|
343 |
- welDynamicCommentBtn.html("@Messages("button.nextState."+issue.nextState().toString.toLowerCase)") |
|
344 |
- .on("click", function(){ |
|
345 |
- if(welEditor.val().length > 0){ |
|
346 |
- welWithStateTransition.val("true"); |
|
347 |
- welCommentForm.attr("action", "@routes.IssueApp.newCommentWithState(project.owner, project.name, issue.getNumber)"); |
|
348 |
- welCommentForm.submit(); |
|
349 |
- } else { |
|
350 |
- welWithStateTransition.val(""); |
|
351 |
- location.href="@routes.IssueApp.nextState(project.owner, project.name, issue.getNumber)"; |
|
352 |
- } |
|
353 |
- }); |
|
354 |
- welEditor.on("keyup", function(){ |
|
355 |
- if(welEditor.val().length > 0){ |
|
356 |
- welDynamicCommentBtn.html(sCommentAndNextState); |
|
357 |
- } else { |
|
358 |
- welDynamicCommentBtn.html(sNextState); |
|
359 |
- } |
|
360 | 330 |
}); |
361 | 331 |
}); |
362 | 332 |
</script> |
--- public/javascripts/common/yobi.Pagination.js
+++ public/javascripts/common/yobi.Pagination.js
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 |
yobi.Pagination = (function(window, document) { |
17 | 17 |
var htRegEx = {}; |
18 | 18 |
var rxDigit = /^.[0-9]*$/; |
19 |
+ // $.isNumeric determines hex, point or negative numbers as numeric. |
|
20 |
+ // but, rxDigit finds only positive decimal integer numbers |
|
19 | 21 |
|
20 | 22 |
/** |
21 | 23 |
* getQuery |
... | ... | @@ -88,102 +90,189 @@ |
88 | 90 |
} |
89 | 91 |
|
90 | 92 |
/** |
91 |
- * window.updatePagination |
|
93 |
+ * Update pagination |
|
94 |
+ * |
|
95 |
+ * @param {HTMLElement} elTarget |
|
96 |
+ * @param {Number} nTotalPages |
|
97 |
+ * @param {Hash Table} htOpt |
|
92 | 98 |
*/ |
93 |
- window.updatePagination = function(target, totalPages, options) { |
|
94 |
- if (totalPages <= 0){ |
|
99 |
+ function updatePagination(elTarget, nTotalPages, htOptions) { |
|
100 |
+ if (nTotalPages <= 0){ |
|
95 | 101 |
return; |
96 | 102 |
} |
97 | 103 |
|
98 |
- var target = $(target); |
|
99 |
- var linkToPrev, linkToNext, urlToPrevPage, urlToNextPage; |
|
100 |
- var options = options || {}; |
|
104 |
+ var welTarget = $(elTarget); |
|
105 |
+ var htData = htOptions || {}; |
|
101 | 106 |
|
102 |
- options.url = options.url || document.URL; |
|
103 |
- options.firstPage = options.firstPage || 1; |
|
107 |
+ htData.url = htData.url || document.URL; |
|
108 |
+ htData.firstPage = htData.firstPage || 1; |
|
109 |
+ htData.totalPages = nTotalPages; |
|
110 |
+ htData.paramNameForPage = htData.paramNameForPage || 'pageNum'; |
|
111 |
+ htData.current = !rxDigit.test(htData.current) ? _getPageNumFromUrl(htData) : htData.current; |
|
112 |
+ htData.hasPrev = (typeof htData.hasPrev === "undefined") ? htData.current > htData.firstPage : htData.hasPrev; |
|
113 |
+ htData.hasNext = (typeof htData.hasNext === "undefined") ? htData.current < htData.totalPages : htData.hasNext; |
|
104 | 114 |
|
105 |
- var pageNumFromUrl; |
|
106 |
- var paramNameForPage = options.paramNameForPage || 'pageNum'; |
|
115 |
+ validateOptions(htData); |
|
107 | 116 |
|
108 |
- if (!$.isNumeric(options.current)) { |
|
109 |
- query = getQuery(options.url); |
|
110 |
- pageNumFromUrl = parseInt(valueFromQuery(paramNameForPage, query)); |
|
111 |
- options.current = pageNumFromUrl || options.firstPage; |
|
112 |
- } |
|
117 |
+ welTarget.html(''); |
|
118 |
+ welTarget.addClass('page-navigation-wrap'); |
|
113 | 119 |
|
114 |
- options.hasPrev = (typeof options.hasPrev == "undefined") ? options.current > options.firstPage : options.hasPrev; |
|
115 |
- options.hasNext = (typeof options.hasNext == "undefined") ? options.current < totalPages : options.hasNext; |
|
116 |
- |
|
117 |
- validateOptions(options); |
|
118 |
- |
|
119 |
- target.html(''); |
|
120 |
- target.addClass('page-navigation-wrap'); |
|
121 |
- |
|
122 |
- // previous page exists |
|
123 |
- var welPagePrev; |
|
124 |
- if (options.hasPrev) { |
|
125 |
- linkToPrev = $('<a pjax-page>').append($('<i class="ico btn-pg-prev">')).append($('<span>').text('PREV')); |
|
126 |
- |
|
127 |
- if (typeof (options.submit) == 'function') { |
|
128 |
- linkToPrev.attr('href', 'javascript: void(0);').click(function(e) { |
|
129 |
- options.submit(options.current - 1); |
|
130 |
- }); |
|
131 |
- } else { |
|
132 |
- urlToPrevPage = urlWithPageNum(options.url, options.current - 1, paramNameForPage); |
|
133 |
- linkToPrev.attr('href', urlToPrevPage); |
|
134 |
- } |
|
135 |
- |
|
136 |
- welPagePrev = $('<li class="page-num ikon">').append(linkToPrev); |
|
137 |
- } else { |
|
138 |
- welPagePrev = $('<li class="page-num ikon">').append($('<i class="ico btn-pg-prev off">')).append($('<span class="off">').text('PREV')); |
|
139 |
- } |
|
140 |
- |
|
141 |
- // on submit event handler |
|
142 |
- if (typeof (options.submit) == 'function') { |
|
143 |
- var keydownOnInput = function(e) { |
|
144 |
- if(validateInputNum($(target), options.current)){ |
|
145 |
- options.submit($(target).val()); |
|
146 |
- } |
|
147 |
- }; |
|
148 |
- } else { |
|
149 |
- var keydownOnInput = function(e) { |
|
150 |
- var welTarget = $(e.target || e.srcElement); |
|
151 |
- if (e.which == 13 && validateInputNum(welTarget, options.current)) { |
|
152 |
- document.location.href = urlWithPageNum(options.url, welTarget.val(), paramNameForPage); |
|
153 |
- } |
|
154 |
- } |
|
155 |
- } |
|
120 |
+ // prev/next link |
|
121 |
+ var welPagePrev = _getPrevPageLink(htData); |
|
122 |
+ var welPageNext = _getNextPageLink(htData); |
|
156 | 123 |
|
157 | 124 |
// page input box |
158 |
- var elInput = $('<input name="pageNum" type="number" pattern="[0-9]*" min="1" max="' + totalPages + '" class="input-mini" value="' + options.current + '">').keydown(keydownOnInput); |
|
159 |
- var welPageInputContainer = $('<li class="page-num">').append(elInput); |
|
125 |
+ var welPageInput = _getPageInputBox(htData); |
|
126 |
+ var welPageInputWrap = $('<li class="page-num">').append(welPageInput); |
|
160 | 127 |
var welDelimiter = $('<li class="page-num delimiter">').text('/'); |
161 |
- var welTotalPages = $('<li class="page-num">').text(totalPages); |
|
162 |
- |
|
163 |
- // next page exists |
|
164 |
- var welPageNext; |
|
165 |
- if (options.hasNext) { |
|
166 |
- linkToNext = $('<a pjax-page>').append($('<span>').text('NEXT')).append($('<i class="ico btn-pg-next">')); |
|
167 |
- |
|
168 |
- if (typeof (options.submit) == 'function') { |
|
169 |
- linkToNext.attr('href', 'javascript: void(0);').click(function(e) { options.submit(options.current + 1);}); |
|
170 |
- } else { |
|
171 |
- urlToNextPage = urlWithPageNum(options.url, options.current + 1, paramNameForPage); |
|
172 |
- linkToNext.attr('href', urlToNextPage); |
|
173 |
- } |
|
174 |
- |
|
175 |
- welPageNext = $('<li class="page-num ikon">').append(linkToNext); |
|
176 |
- } else { |
|
177 |
- welPageNext = $('<li class="page-num ikon">').append($('<span class="off">').text('NEXT').append('<i class="ico btn-pg-next off">')); |
|
178 |
- } |
|
128 |
+ var welTotalPages = $('<li class="page-num">').text(nTotalPages); |
|
179 | 129 |
|
180 | 130 |
// fill #pagination |
181 |
- var welPageList = $('<ul class="page-nums">').append([welPagePrev, welPageInputContainer, welDelimiter, welTotalPages, welPageNext]); |
|
182 |
- target.append(welPageList); |
|
183 |
- }; |
|
131 |
+ var welPageList = $('<ul class="page-nums">'); |
|
132 |
+ welPageList.append([welPagePrev, welPageInputWrap, welDelimiter, welTotalPages, welPageNext]); |
|
133 |
+ welTarget.append(welPageList); |
|
134 |
+ } |
|
135 |
+ |
|
136 |
+ /** |
|
137 |
+ * Get current page number from QueryString |
|
138 |
+ * |
|
139 |
+ * @param htData |
|
140 |
+ * @returns {Number} |
|
141 |
+ * @private |
|
142 |
+ */ |
|
143 |
+ function _getPageNumFromUrl(htData){ |
|
144 |
+ var sQuery = getQuery(htData.url); |
|
145 |
+ var nPageNumFromUrl = parseInt(valueFromQuery(htData.paramNameForPage, sQuery), 10); |
|
146 |
+ return nPageNumFromUrl || htData.firstPage; |
|
147 |
+ } |
|
148 |
+ |
|
149 |
+ /** |
|
150 |
+ * Get PageNum INPUT element |
|
151 |
+ * |
|
152 |
+ * @param htData |
|
153 |
+ * @returns {Wrapped Element} |
|
154 |
+ * @private |
|
155 |
+ */ |
|
156 |
+ function _getPageInputBox(htData){ |
|
157 |
+ var welPageInput = $('<input type="number" pattern="[0-9]*" class="input-mini">'); |
|
158 |
+ |
|
159 |
+ welPageInput.prop({ |
|
160 |
+ "name" : htData.paramNameForPage, |
|
161 |
+ "max" : htData.totalPages, |
|
162 |
+ "min" : 1 |
|
163 |
+ }); |
|
164 |
+ |
|
165 |
+ welPageInput.val(htData.current); |
|
166 |
+ |
|
167 |
+ welPageInput.on("keydown", function(weEvt){ |
|
168 |
+ if(!isValidInputNum(welPageInput, htData.current)){ |
|
169 |
+ return; |
|
170 |
+ } |
|
171 |
+ |
|
172 |
+ var nCurrentValue = welPageInput.val(); |
|
173 |
+ |
|
174 |
+ if(typeof htData.submit === "function"){ |
|
175 |
+ htData.submit(nCurrentValue); |
|
176 |
+ } else if(weEvt.which === 13){ |
|
177 |
+ document.location.href = urlWithPageNum(htData.url, nCurrentValue, htData.paramNameForPage); |
|
178 |
+ } |
|
179 |
+ }); |
|
180 |
+ |
|
181 |
+ return welPageInput; |
|
182 |
+ } |
|
183 |
+ |
|
184 |
+ /** |
|
185 |
+ * Get previous page link |
|
186 |
+ * |
|
187 |
+ * @param htData |
|
188 |
+ * @returns {Wrapped Element} |
|
189 |
+ * @private |
|
190 |
+ */ |
|
191 |
+ function _getPrevPageLink(htData){ |
|
192 |
+ var sLinkText = Messages("button.prevPage") || 'PREV'; |
|
193 |
+ var sLinkHTMLOn = '<i class="ico btn-pg-prev"></i><span>' + sLinkText + '</span>'; |
|
194 |
+ var sLinkHTMLOff = '<i class="ico btn-pg-prev off"></i><span class="off">' + sLinkText + '</span>'; |
|
195 |
+ |
|
196 |
+ var htOptions = $.extend(htData, { |
|
197 |
+ "bActive" : htData.hasPrev, |
|
198 |
+ "sLinkHref": htData.hasPrev ? urlWithPageNum(htData.url, htData.current - 1, htData.paramNameForPage) : "", |
|
199 |
+ "sLinkHTMLOn" : sLinkHTMLOn, |
|
200 |
+ "sLinkHTMLOff" : sLinkHTMLOff, |
|
201 |
+ "sShortcutKey" : "A", |
|
202 |
+ "nSubmitPageNum": htData.current - 1 |
|
203 |
+ }); |
|
204 |
+ |
|
205 |
+ var welPagePrev = _buildPageLink(htOptions); |
|
206 |
+ |
|
207 |
+ return welPagePrev; |
|
208 |
+ } |
|
209 |
+ |
|
210 |
+ /** |
|
211 |
+ * Get next page link |
|
212 |
+ * |
|
213 |
+ * @param htData |
|
214 |
+ * @returns {Wrapped Element} |
|
215 |
+ * @private |
|
216 |
+ */ |
|
217 |
+ function _getNextPageLink(htData){ |
|
218 |
+ var sLinkText = Messages("button.nextPage") || 'NEXT'; |
|
219 |
+ var sLinkHTMLOn = '<span>' + sLinkText + '</span><i class="ico btn-pg-next"></i>'; |
|
220 |
+ var sLinkHTMLOff = '<span class="off">' + sLinkText + '</span><i class="ico btn-pg-next off"></i>'; |
|
221 |
+ |
|
222 |
+ var htOptions = $.extend(htData, { |
|
223 |
+ "bActive" : htData.hasNext, |
|
224 |
+ "sLinkHref": htData.hasNext ? urlWithPageNum(htData.url, htData.current + 1, htData.paramNameForPage) : "", |
|
225 |
+ "sLinkHTMLOn" : sLinkHTMLOn, |
|
226 |
+ "sLinkHTMLOff" : sLinkHTMLOff, |
|
227 |
+ "sShortcutKey" : "S", |
|
228 |
+ "nSubmitPageNum": htData.current + 1 |
|
229 |
+ }); |
|
230 |
+ |
|
231 |
+ var welPageNext = _buildPageLink(htOptions); |
|
232 |
+ |
|
233 |
+ return welPageNext; |
|
234 |
+ } |
|
235 |
+ |
|
236 |
+ /** |
|
237 |
+ * Build prev/next page link |
|
238 |
+ * |
|
239 |
+ * @param htData |
|
240 |
+ * @returns {Wrapped Element} |
|
241 |
+ * @private |
|
242 |
+ */ |
|
243 |
+ function _buildPageLink(htData){ |
|
244 |
+ var welPageLink = $('<li class="page-num ikon">'); |
|
245 |
+ |
|
246 |
+ if(htData.bActive){ |
|
247 |
+ var welLink = $('<a pjax-page>'); |
|
248 |
+ welLink.html(htData.sLinkHTMLOn); |
|
249 |
+ |
|
250 |
+ if(typeof htData.submit === 'function'){ |
|
251 |
+ welLink.attr("href", "javascript: void(0);"); |
|
252 |
+ welLink.on("click", function(){ |
|
253 |
+ htData.submit(htData.nSubmitPageNum); |
|
254 |
+ }); |
|
255 |
+ } else { |
|
256 |
+ welLink.attr("href", htData.sLinkHref); |
|
257 |
+ } |
|
258 |
+ |
|
259 |
+ welPageLink.append(welLink); |
|
260 |
+ } else { |
|
261 |
+ welPageLink.html(htData.sLinkHTMLOff); |
|
262 |
+ } |
|
263 |
+ |
|
264 |
+ // if yobi.ShortcutKey exists |
|
265 |
+ if(yobi.ShortcutKey){ |
|
266 |
+ var htKeyOpt = {}; |
|
267 |
+ htKeyOpt[htData.sShortcutKey] = htData.sLinkHref; |
|
268 |
+ yobi.ShortcutKey.setKeymapLink(htKeyOpt); |
|
269 |
+ } |
|
270 |
+ |
|
271 |
+ return welPageLink; |
|
272 |
+ } |
|
184 | 273 |
|
185 | 274 |
// validate number range |
186 |
- function validateInputNum(welTarget, nCurrentPageNum){ |
|
275 |
+ function isValidInputNum(welTarget, nCurrentPageNum){ |
|
187 | 276 |
if(rxDigit.test(welTarget.val()) === false){ |
188 | 277 |
welTarget.val(nCurrentPageNum); |
189 | 278 |
return false; |
--- public/javascripts/common/yobi.ShortcutKey.js
+++ public/javascripts/common/yobi.ShortcutKey.js
... | ... | @@ -24,6 +24,7 @@ |
24 | 24 |
*/ |
25 | 25 |
function _initVar(){ |
26 | 26 |
htVar.rxTrim = /\s+/g; |
27 |
+ htVar.aFormTags = ["INPUT", "TEXTAREA"]; |
|
27 | 28 |
htVar.aCombinationKeys = ["CTRL", "ALT", "SHIFT"]; |
28 | 29 |
htVar.htKeycodeMap = { |
29 | 30 |
'13':'ENTER', '38':'UP', '40':'DOWN', '37':'LEFT', '39':'RIGHT', '13':'ENTER', '27':'ESC', |
... | ... | @@ -40,13 +41,17 @@ |
40 | 41 |
* add event listener |
41 | 42 |
*/ |
42 | 43 |
function _attachEvent(){ |
43 |
- $(window).bind("keydown", _onKeyDown); |
|
44 |
- $(window).bind("beforeunload", destroy); // free memory |
|
44 |
+ $(window).on({ |
|
45 |
+ "keydown" : _onKeyDown, |
|
46 |
+ "beforeunload": destroy // free memory |
|
47 |
+ }); |
|
45 | 48 |
} |
46 | 49 |
|
47 | 50 |
function _detachEvent(){ |
48 |
- $(window).unbind("keydown", _onKeyDown); |
|
49 |
- $(window).unbind("beforeunload", destroy); |
|
51 |
+ $(window).off({ |
|
52 |
+ "keydown" : _onKeyDown, |
|
53 |
+ "beforeunload": destroy // free memory |
|
54 |
+ }); |
|
50 | 55 |
} |
51 | 56 |
|
52 | 57 |
/** |
... | ... | @@ -54,24 +59,25 @@ |
54 | 59 |
*/ |
55 | 60 |
function _onKeyDown(weEvt){ |
56 | 61 |
var sKeyInput = _getKeyString(weEvt); |
57 |
- var aHandlers = htHandlers[sKeyInput] || []; |
|
62 |
+ var fHandler = htHandlers[sKeyInput]; |
|
58 | 63 |
|
59 |
- _runEventHandler(aHandlers, weEvt, sKeyInput); |
|
64 |
+ if(typeof fHandler === "function"){ |
|
65 |
+ _runEventHandler(fHandler, weEvt, sKeyInput); |
|
66 |
+ } |
|
60 | 67 |
} |
61 | 68 |
|
62 |
- function _runEventHandler(aHandlers, weEvt, sKeyInput){ |
|
69 |
+ function _runEventHandler(fHandler, weEvt, sKeyInput){ |
|
70 |
+ var sTagName = weEvt.target.tagName.toUpperCase(); |
|
63 | 71 |
var htInfo = { |
64 | 72 |
"weEvt" : weEvt, |
65 | 73 |
"welTarget" : $(weEvt.target), |
66 |
- "sTagName" : weEvt.target.tagName, |
|
74 |
+ "sTagName" : sTagName, |
|
67 | 75 |
"sKeyInput" : sKeyInput, |
68 |
- "bFormInput": (weEvt.target.tagName == "INPUT" || weEvt.target.tagName == "TEXTAREA") |
|
76 |
+ "bFormInput": (htVar.aFormTags.indexOf(sTagName) > -1) |
|
69 | 77 |
}; |
70 | 78 |
|
71 | 79 |
try { |
72 |
- aHandlers.forEach(function(fHandler){ |
|
73 |
- fHandler(htInfo); |
|
74 |
- }); |
|
80 |
+ fHandler(htInfo); |
|
75 | 81 |
}catch(e){} finally { |
76 | 82 |
htInfo = null; |
77 | 83 |
} |
... | ... | @@ -85,25 +91,20 @@ |
85 | 91 |
* @param {Hash Table} vKey {"keyCombination:function(){}, "key":function(){}} |
86 | 92 |
*/ |
87 | 93 |
function attachHandler(vKey, fHandler){ |
88 |
- if(typeof vKey == "string"){ |
|
89 |
- return _addHandler(vKey, fHandler); |
|
94 |
+ if(typeof vKey === "string"){ |
|
95 |
+ return _setHandler(vKey, fHandler); |
|
90 | 96 |
} |
91 | 97 |
|
92 |
- var fHandler; |
|
93 |
- for(var sKey in vKey){ |
|
98 |
+ var fHandler, sKey; |
|
99 |
+ for(sKey in vKey){ |
|
94 | 100 |
fHandler = vKey[sKey]; |
95 |
- _addHandler(sKey, fHandler); |
|
101 |
+ _setHandler(sKey, fHandler); |
|
96 | 102 |
} |
97 | 103 |
} |
98 | 104 |
|
99 |
- function _addHandler(sKey, fHandler){ |
|
105 |
+ function _setHandler(sKey, fHandler){ |
|
100 | 106 |
sKey = _normalizeKeyString(sKey); |
101 |
- |
|
102 |
- if(!(htHandlers[sKey] instanceof Array)){ |
|
103 |
- htHandlers[sKey] = []; |
|
104 |
- } |
|
105 |
- |
|
106 |
- htHandlers[sKey].push(fHandler); |
|
107 |
+ htHandlers[sKey] = fHandler; |
|
107 | 108 |
} |
108 | 109 |
|
109 | 110 |
/** |
... | ... | @@ -111,14 +112,9 @@ |
111 | 112 |
* @param {String} sKey |
112 | 113 |
* @param {String} fHandler |
113 | 114 |
*/ |
114 |
- function detachHandler(sKeyInput, fHandler){ |
|
115 |
+ function detachHandler(sKeyInput){ |
|
115 | 116 |
var sKey = _normalizeKeyString(sKeyInput); |
116 |
- var aHandlers = htHandlers[sKey]; |
|
117 |
- |
|
118 |
- if(aHandlers instanceof Array){ |
|
119 |
- aHandlers.splice(aHandlers.indexOf(fHandler), 1); |
|
120 |
- htHandlers[sKey] = aHandlers; |
|
121 |
- } |
|
117 |
+ delete htHandlers[sKey]; |
|
122 | 118 |
} |
123 | 119 |
|
124 | 120 |
/** |
... | ... | @@ -127,7 +123,7 @@ |
127 | 123 |
*/ |
128 | 124 |
function _getKeyString(weEvt){ |
129 | 125 |
var sMainKey = htVar.htKeycodeMap[weEvt.keyCode]; |
130 |
- if(typeof sMainKey == "undefined"){ // ignore event if not on keyMap |
|
126 |
+ if(typeof sMainKey === "undefined"){ // ignore event if not on keyMap |
|
131 | 127 |
return; |
132 | 128 |
} |
133 | 129 |
|
... | ... | @@ -184,12 +180,19 @@ |
184 | 180 |
* }); |
185 | 181 |
*/ |
186 | 182 |
function setKeymapLink(htKeyMap){ |
187 |
- for(var sKey in htKeyMap){ |
|
188 |
- attachHandler(sKey, function(htInfo){ |
|
189 |
- if(!htInfo.bFormInput){ |
|
190 |
- document.location.href = htKeyMap[htInfo.sKeyInput]; |
|
191 |
- } |
|
192 |
- }); |
|
183 |
+ var sKey; |
|
184 |
+ var fHandler = function(htInfo){ |
|
185 |
+ if(!htInfo.bFormInput){ |
|
186 |
+ document.location.href = htKeyMap[htInfo.sKeyInput]; |
|
187 |
+ } |
|
188 |
+ }; |
|
189 |
+ |
|
190 |
+ for(sKey in htKeyMap){ |
|
191 |
+ if(htKeyMap[sKey]){ |
|
192 |
+ attachHandler(sKey, fHandler); |
|
193 |
+ } else { |
|
194 |
+ detachHandler(sKey); |
|
195 |
+ } |
|
193 | 196 |
} |
194 | 197 |
} |
195 | 198 |
|
--- public/javascripts/service/yobi.issue.View.js
+++ public/javascripts/service/yobi.issue.View.js
... | ... | @@ -29,6 +29,8 @@ |
29 | 29 |
_setLabelTextColor(); |
30 | 30 |
|
31 | 31 |
_setTimelineUpdateTimer(); |
32 |
+ |
|
33 |
+ _setBtnCommentAndClose(); |
|
32 | 34 |
} |
33 | 35 |
|
34 | 36 |
/** |
... | ... | @@ -71,6 +73,11 @@ |
71 | 73 |
htVar.sTimelineHTML = htElement.welTimelineList.html(); |
72 | 74 |
htVar.nTimelineItems = _countTimelineItems(); // 타임라인 항목 갯수 |
73 | 75 |
htVar.bOnFocusTextarea = false; // 댓글 작성폼에 포커스가 있는지 여부 |
76 |
+ |
|
77 |
+ // for comment-and-close |
|
78 |
+ htVar.sNextState = htOptions.sNextState; |
|
79 |
+ htVar.sNextStateUrl = htOptions.sNextStateUrl; |
|
80 |
+ htVar.sCommentWithStateUrl = htOptions.sCommentWithStateUrl; |
|
74 | 81 |
} |
75 | 82 |
|
76 | 83 |
/** |
... | ... | @@ -390,6 +397,51 @@ |
390 | 397 |
return htElement.welTimelineList.find("ul.comments > li").length; |
391 | 398 |
} |
392 | 399 |
|
400 |
+ /** |
|
401 |
+ * Add "comment & close" like button at comment form |
|
402 |
+ * @private |
|
403 |
+ */ |
|
404 |
+ function _setBtnCommentAndClose(){ |
|
405 |
+ var welEditor = $("#comment-editor"); |
|
406 |
+ var welDynamicCommentBtn = $("#dynamic-comment-btn"); |
|
407 |
+ var welCommentForm = $("#comment-form"); |
|
408 |
+ var welWithStateTransition = $("<input type='hidden' name='withStateTransition'>"); |
|
409 |
+ |
|
410 |
+ var sNextState = Messages("button.nextState." + htVar.sNextState); |
|
411 |
+ var sCommentAndNextState = Messages("button.commentAndNextState." + htVar.sNextState); |
|
412 |
+ |
|
413 |
+ welCommentForm.prepend(welWithStateTransition); |
|
414 |
+ welDynamicCommentBtn.removeClass('hidden'); |
|
415 |
+ welDynamicCommentBtn.html(Messages("button.nextState." + htVar.sNextState)); |
|
416 |
+ welDynamicCommentBtn.on("click", function(){ |
|
417 |
+ if(welEditor.val().length > 0){ |
|
418 |
+ welWithStateTransition.val("true"); |
|
419 |
+ welCommentForm.attr("action", htVar.sCommentWithStateUrl); |
|
420 |
+ welCommentForm.submit(); |
|
421 |
+ } else { |
|
422 |
+ welWithStateTransition.val(""); |
|
423 |
+ location.href = htVar.sNextStateUrl; |
|
424 |
+ } |
|
425 |
+ }); |
|
426 |
+ |
|
427 |
+ welEditor.on("keyup", function(){ |
|
428 |
+ if(welEditor.val().length > 0){ |
|
429 |
+ welDynamicCommentBtn.html(sCommentAndNextState); |
|
430 |
+ } else { |
|
431 |
+ welDynamicCommentBtn.html(sNextState); |
|
432 |
+ } |
|
433 |
+ }); |
|
434 |
+ |
|
435 |
+ // if yobi.ShortcutKey exists |
|
436 |
+ if(yobi.ShortcutKey){ |
|
437 |
+ yobi.ShortcutKey.attach("CTRL+SHIFT+ENTER", function(htInfo){ |
|
438 |
+ if(htInfo.welTarget.is(welEditor)){ |
|
439 |
+ welDynamicCommentBtn.click(); |
|
440 |
+ } |
|
441 |
+ }); |
|
442 |
+ } |
|
443 |
+ } |
|
444 |
+ |
|
393 | 445 |
// initialize |
394 | 446 |
_init(htOptions || {}); |
395 | 447 |
}; |
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?