narou 2.6.1 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of narou might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/ChangeLog.md +65 -0
- data/README.md +69 -22
- data/lib/command.rb +1 -0
- data/lib/command/alias.rb +2 -2
- data/lib/command/convert.rb +3 -3
- data/lib/command/csv.rb +108 -0
- data/lib/command/download.rb +13 -1
- data/lib/command/freeze.rb +1 -1
- data/lib/command/init.rb +5 -1
- data/lib/command/inspect.rb +1 -1
- data/lib/command/mail.rb +1 -1
- data/lib/command/send.rb +2 -2
- data/lib/command/setting.rb +17 -1
- data/lib/command/tag.rb +28 -9
- data/lib/command/update.rb +57 -30
- data/lib/commandbase.rb +3 -2
- data/lib/commandline.rb +2 -2
- data/lib/converterbase.rb +70 -7
- data/lib/database.rb +1 -1
- data/lib/device.rb +3 -0
- data/lib/device/ibooks.rb +2 -2
- data/lib/device/ibunko.rb +4 -0
- data/lib/diffviewer.rb +2 -2
- data/lib/downloader.rb +16 -9
- data/lib/helper.rb +53 -22
- data/lib/inventory.rb +6 -2
- data/lib/narou.rb +13 -6
- data/lib/novelconverter.rb +35 -13
- data/lib/novelsetting.rb +7 -1
- data/lib/version.rb +1 -1
- data/lib/web/appserver.rb +78 -8
- data/lib/web/public/resources/common.ui.js +0 -39
- data/lib/web/public/resources/dataTables.colVis.js +1 -1
- data/lib/web/public/resources/default-style.css +1 -1
- data/lib/web/public/resources/help/bookmarklet1.png +0 -0
- data/lib/web/public/resources/help/bookmarklet2.png +0 -0
- data/lib/web/public/resources/images/dl_button0.gif +0 -0
- data/lib/web/public/resources/images/dl_button1.gif +0 -0
- data/lib/web/public/resources/narou.library.js +268 -36
- data/lib/web/public/resources/narou.queue.js +51 -0
- data/lib/web/public/resources/narou.ui.js +156 -59
- data/lib/web/settingmessages.rb +2 -1
- data/lib/web/views/{js/widget.erb → bookmarklet/download.js.erb} +1 -1
- data/lib/web/views/bookmarklet/insert_button.js.erb +133 -0
- data/lib/web/views/help.haml +31 -14
- data/lib/web/views/index.haml +62 -0
- data/lib/web/views/layout.haml +8 -7
- data/lib/web/views/parts/csv_import.haml +68 -0
- data/lib/web/views/parts/download_form.haml +89 -0
- data/lib/web/views/settings.haml +8 -3
- data/lib/web/views/style.scss +200 -14
- data/lib/web/views/{widget.haml → widget/download.haml} +18 -4
- data/lib/web/views/widget/drag_and_drop.haml +97 -0
- data/lib/web/worker.rb +39 -1
- data/narou.gemspec +56 -56
- data/preset/custom_chuki_tag.txt +1 -1
- data/preset/doubledash.png +0 -0
- data/preset/singledash.png +0 -0
- data/preset/vertical_font.css +1 -1
- data/spec/convert_spec.rb +5 -1
- data/spec/data/convert_test/auto_join_line/correct_test_auto_join_line.txt +6 -0
- data/spec/data/convert_test/auto_join_line/test_auto_join_line.txt +8 -0
- data/spec/data/convert_test/double_dash_to_image/correct_test_double_dash_to_image.txt +14 -0
- data/spec/data/convert_test/double_dash_to_image/setting.ini +1 -0
- data/spec/data/convert_test/double_dash_to_image/test_double_dash_to_image.txt +12 -0
- data/spec/worker_spec.rb +21 -2
- metadata +97 -60
data/lib/novelsetting.rb
CHANGED
@@ -101,7 +101,7 @@ class NovelSetting
|
|
101
101
|
# { name: value, ... } 形式のハッシュとして返す
|
102
102
|
#
|
103
103
|
def self.load_settings_by_pattern(pattern)
|
104
|
-
res = Inventory.load("local_setting"
|
104
|
+
res = Inventory.load("local_setting").map { |name, value|
|
105
105
|
if name =~ /^#{pattern}\.(.+)$/
|
106
106
|
[$1, value]
|
107
107
|
else
|
@@ -430,6 +430,12 @@ class NovelSetting
|
|
430
430
|
value: false,
|
431
431
|
help: "HTMLの装飾系タグを削除する(主にArcadiaの作品に影響)"
|
432
432
|
},
|
433
|
+
{
|
434
|
+
name: "enable_double_dash_to_image",
|
435
|
+
type: :boolean,
|
436
|
+
value: false,
|
437
|
+
help: "2倍ダッシュ(――)を画像に差し替える。Kindleのデフォルトフォントみたいにダッシュが太くて気になる人用"
|
438
|
+
},
|
433
439
|
]
|
434
440
|
|
435
441
|
ORIGINAL_SETTINGS_KEY_INDEXES = {}.tap { |hash|
|
data/lib/version.rb
CHANGED
data/lib/web/appserver.rb
CHANGED
@@ -419,6 +419,10 @@ class Narou::AppServer < Sinatra::Base
|
|
419
419
|
json json_objects
|
420
420
|
end
|
421
421
|
|
422
|
+
post "/api/cancel" do
|
423
|
+
Narou::Worker.cancel
|
424
|
+
end
|
425
|
+
|
422
426
|
post "/api/convert" do
|
423
427
|
ids = select_valid_novel_ids(params["ids"]) or pass
|
424
428
|
Narou::Worker.push do
|
@@ -428,7 +432,7 @@ class Narou::AppServer < Sinatra::Base
|
|
428
432
|
|
429
433
|
post "/api/download" do
|
430
434
|
targets = params["targets"] or pass
|
431
|
-
targets = targets.split
|
435
|
+
targets = targets.kind_of?(Array) ? targets : targets.split
|
432
436
|
pass if targets.size == 0
|
433
437
|
Narou::Worker.push do
|
434
438
|
CommandLine.run!(["download"] + targets)
|
@@ -527,6 +531,14 @@ class Narou::AppServer < Sinatra::Base
|
|
527
531
|
haml :diff_list, layout: false
|
528
532
|
end
|
529
533
|
|
534
|
+
post "/api/diff_clean" do
|
535
|
+
target = params["target"] or pass
|
536
|
+
id = Downloader.get_id_by_target(target) or pass
|
537
|
+
Narou::Worker.push do
|
538
|
+
CommandLine.run!(%W(diff --clean #{id}))
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
530
542
|
post "/api/inspect" do
|
531
543
|
ids = select_valid_novel_ids(params["ids"]) or pass
|
532
544
|
Narou::Worker.push do
|
@@ -554,7 +566,9 @@ class Narou::AppServer < Sinatra::Base
|
|
554
566
|
result = '<div><span class="tag label label-default" data-tag="">タグ検索を解除</span></div>'
|
555
567
|
tagname_list = Command::Tag.get_tag_list.keys
|
556
568
|
tagname_list.each do |tagname|
|
557
|
-
result << "<div>#{decorate_tags([tagname])}
|
569
|
+
result << "<div>#{decorate_tags([tagname])} " \
|
570
|
+
"<span class='select-color-button' data-target-tag='#{h tagname}'>" \
|
571
|
+
"<span class='#{Command::Tag.get_color(tagname)}'>a</span></span></div>"
|
558
572
|
end
|
559
573
|
result
|
560
574
|
end
|
@@ -622,14 +636,69 @@ class Narou::AppServer < Sinatra::Base
|
|
622
636
|
end
|
623
637
|
end
|
624
638
|
|
639
|
+
post "/api/change_tag_color" do
|
640
|
+
tag = params["tag"] or pass
|
641
|
+
color = params["color"] or pass
|
642
|
+
tag_colors = Inventory.load("tag_colors")
|
643
|
+
tag_colors[tag] = color
|
644
|
+
tag_colors.save
|
645
|
+
@@push_server.send_all(:"table.reload")
|
646
|
+
@@push_server.send_all(:"tag.updateCanvas")
|
647
|
+
end
|
648
|
+
|
649
|
+
get "/api/csv/download" do
|
650
|
+
content_type "application/csv"
|
651
|
+
attachment "novels.csv"
|
652
|
+
|
653
|
+
Command::Csv.new.generate
|
654
|
+
end
|
655
|
+
|
656
|
+
post "/api/csv/import" do
|
657
|
+
files = params["files"] or pass
|
658
|
+
csv = Command::Csv.new
|
659
|
+
files.each do |file|
|
660
|
+
csv.import(file[:tempfile])
|
661
|
+
end
|
662
|
+
""
|
663
|
+
end
|
664
|
+
|
665
|
+
# ダウンロード登録すると同時にグレーのボタン画像を返す
|
666
|
+
get "/api/download4ie" do
|
667
|
+
Narou::Worker.push do
|
668
|
+
CommandLine.run!(%W(download #{params["target"]}))
|
669
|
+
@@push_server.send_all(:"table.reload")
|
670
|
+
end
|
671
|
+
redirect "/resources/images/dl_button1.gif"
|
672
|
+
end
|
673
|
+
|
674
|
+
get "/api/validate_url_regexp_list" do
|
675
|
+
json Downloader.load_settings.map { |setting|
|
676
|
+
"(#{setting["url"].gsub(/\?<.+?>/, "?:").gsub("\\", "\\\\")})"
|
677
|
+
}
|
678
|
+
end
|
679
|
+
|
680
|
+
# -------------------------------------------------------------------------------
|
681
|
+
# 一部分に表示するためのHTMLを取得する
|
682
|
+
# -------------------------------------------------------------------------------
|
683
|
+
|
684
|
+
get "/parts/csv_import" do
|
685
|
+
haml :"parts/csv_import", layout: false
|
686
|
+
end
|
687
|
+
|
688
|
+
get "/parts/download_form" do
|
689
|
+
haml :"parts/download_form", layout: false
|
690
|
+
end
|
691
|
+
|
625
692
|
# -------------------------------------------------------------------------------
|
626
693
|
# ウィジット関係
|
627
694
|
# -------------------------------------------------------------------------------
|
628
695
|
|
696
|
+
BOOKMARKLET_MODE = %w(download insert_button)
|
697
|
+
|
629
698
|
get "/js/widget.js" do
|
630
|
-
if
|
699
|
+
if BOOKMARKLET_MODE.include?(params["mode"])
|
631
700
|
content_type :js
|
632
|
-
erb :"js
|
701
|
+
erb :"bookmarklet/#{params['mode']}.js"
|
633
702
|
else
|
634
703
|
error("invaid mode")
|
635
704
|
end
|
@@ -646,9 +715,6 @@ class Narou::AppServer < Sinatra::Base
|
|
646
715
|
from = params["from"]
|
647
716
|
if ALLOW_HOSTS.include?(from)
|
648
717
|
headers "X-Frame-Options" => "ALLOW-FROM http://#{from}/"
|
649
|
-
else
|
650
|
-
headers "X-Frame-Options" => "DENY"
|
651
|
-
halt
|
652
718
|
end
|
653
719
|
end
|
654
720
|
|
@@ -658,7 +724,11 @@ class Narou::AppServer < Sinatra::Base
|
|
658
724
|
CommandLine.run!(["download", target])
|
659
725
|
@@push_server.send_all(:"table.reload")
|
660
726
|
end
|
661
|
-
haml :widget, :
|
727
|
+
haml :"widget/download", layout: nil
|
728
|
+
end
|
729
|
+
|
730
|
+
get "/widget/drag_and_drop" do
|
731
|
+
haml :"widget/drag_and_drop", layout: nil
|
662
732
|
end
|
663
733
|
end
|
664
734
|
|
@@ -28,45 +28,6 @@ $(document).ready(function() {
|
|
28
28
|
*/
|
29
29
|
$("#fadeout-alert").delay(2000).animate({ opacity: "hide" }, 1500);
|
30
30
|
|
31
|
-
/*
|
32
|
-
* キューに積まれた数を表示
|
33
|
-
*/
|
34
|
-
var notification = Narou.Notification.instance();
|
35
|
-
var $queue = $("#queue");
|
36
|
-
function highlightQueuBoxIcon(size) {
|
37
|
-
if (size > 0) {
|
38
|
-
$("#queue-text").addClass("active");
|
39
|
-
}
|
40
|
-
else {
|
41
|
-
$("#queue-text").removeClass("active");
|
42
|
-
}
|
43
|
-
}
|
44
|
-
notification.on("notification.queue", function(data) {
|
45
|
-
var before_size = $queue.text();
|
46
|
-
$queue.text(data);
|
47
|
-
highlightQueuBoxIcon(data);
|
48
|
-
// キューのスタック数の横に +1 が浮かび上がって消えるアニメーション
|
49
|
-
var diff = data - before_size;
|
50
|
-
if (diff <= 0) return;
|
51
|
-
var $plus = $("<span>+" + diff + "</span>");
|
52
|
-
$plus.addClass("queue-plus").css({
|
53
|
-
position: "absolute",
|
54
|
-
left: $queue.offset().left + $queue.outerWidth() + 1 - $(document).scrollLeft(),
|
55
|
-
top: $queue.offset().top - 3 - $(document).scrollTop(),
|
56
|
-
});
|
57
|
-
$(".navbar").append($plus);
|
58
|
-
$plus.delay(100).animate({
|
59
|
-
top: - $plus.outerHeight(),
|
60
|
-
opacity: 0,
|
61
|
-
}, 3000, function() {
|
62
|
-
$(this).remove();
|
63
|
-
});
|
64
|
-
});
|
65
|
-
$.get("/api/get_queue_size", function(json) {
|
66
|
-
$queue.text(json.size);
|
67
|
-
highlightQueuBoxIcon(json.size);
|
68
|
-
});
|
69
|
-
|
70
31
|
/*************************************************************************
|
71
32
|
* Webサーバの方から入力を求められた時にモーダルを表示して返事を返す
|
72
33
|
*************************************************************************/
|
@@ -605,7 +605,7 @@ ColVis.prototype = {
|
|
605
605
|
'<li '+(dt.bJUI ? 'class="ui-button ui-state-default"' : '')+'>'+
|
606
606
|
'<label>'+
|
607
607
|
'<input type="checkbox" />'+
|
608
|
-
'<span>'+title+'</span>'+
|
608
|
+
'<span>'+title.replace("<br>", "")+'</span>'+
|
609
609
|
'</label>'+
|
610
610
|
'</li>'
|
611
611
|
)
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -10,6 +10,13 @@ var Narou = (function() {
|
|
10
10
|
var storage_cache = null;
|
11
11
|
var storage = null;
|
12
12
|
|
13
|
+
$.ajaxSetup({
|
14
|
+
cache: false // IE でキャッシュさせないため
|
15
|
+
});
|
16
|
+
|
17
|
+
// jQuery はデフォルトだと dataTransfer オブジェクトをコピーしないので
|
18
|
+
$.event.props.push("dataTransfer");
|
19
|
+
|
13
20
|
/*************************************************************************
|
14
21
|
* ローカルストレージ
|
15
22
|
*************************************************************************/
|
@@ -90,6 +97,24 @@ var Narou = (function() {
|
|
90
97
|
}
|
91
98
|
return format;
|
92
99
|
},
|
100
|
+
|
101
|
+
get_event_position: function(e) {
|
102
|
+
if (e.type !== "touchstart") {
|
103
|
+
return { x: e.pageX, y: e.pageY };
|
104
|
+
}
|
105
|
+
else {
|
106
|
+
return { x: e.originalEvent.touches[0].pageX,
|
107
|
+
y: e.originalEvent.touches[0].pageY };
|
108
|
+
}
|
109
|
+
},
|
110
|
+
|
111
|
+
noScroll: function() {
|
112
|
+
$("html, body").css("overflow", "hidden");
|
113
|
+
},
|
114
|
+
|
115
|
+
allowScroll: function() {
|
116
|
+
$("html, body").css("overflow", "");
|
117
|
+
},
|
93
118
|
});
|
94
119
|
|
95
120
|
/*************************************************************************
|
@@ -202,11 +227,17 @@ var Narou = (function() {
|
|
202
227
|
$(document).trigger("click");
|
203
228
|
}
|
204
229
|
this.closed = false;
|
230
|
+
var caller = function() {
|
231
|
+
if (typeof callback === "function")
|
232
|
+
callback();
|
233
|
+
};
|
234
|
+
$(document).one("show.bs.dropdown", function() {
|
235
|
+
$("#context-menu").hide();
|
236
|
+
caller();
|
237
|
+
});
|
205
238
|
Narou.popupMenu("#context-menu", pos, function() {
|
206
239
|
$("#context-menu").hide();
|
207
|
-
|
208
|
-
callback();
|
209
|
-
}
|
240
|
+
caller();
|
210
241
|
});
|
211
242
|
},
|
212
243
|
|
@@ -230,12 +261,25 @@ var Narou = (function() {
|
|
230
261
|
|
231
262
|
openSelectDiffListDialog: function(target_id) {
|
232
263
|
$.get("/api/diff_list", { target: target_id }, function(html) {
|
233
|
-
bootbox.dialog({
|
264
|
+
var diff_modal = bootbox.dialog({
|
234
265
|
title: "表示したい差分を選択して下さい",
|
235
266
|
message: html,
|
236
267
|
backdrop: true,
|
237
268
|
className: "diff-list-modal",
|
238
269
|
buttons: {
|
270
|
+
clear: {
|
271
|
+
label: "差分を消去",
|
272
|
+
className: "btn-danger",
|
273
|
+
callback: function() {
|
274
|
+
bootbox.confirm("本当に消去してよろしいですか?", function(result) {
|
275
|
+
if (result) {
|
276
|
+
$.post("/api/diff_clean", { target: target_id });
|
277
|
+
}
|
278
|
+
diff_modal.modal("hide");
|
279
|
+
});
|
280
|
+
return false; // 親モーダルはこの時点では閉じさせない
|
281
|
+
}
|
282
|
+
},
|
239
283
|
main: {
|
240
284
|
label: "閉じる",
|
241
285
|
className: "btn-default"
|
@@ -351,28 +395,39 @@ var Narou = (function() {
|
|
351
395
|
},
|
352
396
|
|
353
397
|
download: function() {
|
354
|
-
var
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
398
|
+
var urls = [];
|
399
|
+
if (typeof arguments !== "undefined" && arguments.length > 0) {
|
400
|
+
urls = Array.prototype.slice.call(arguments);
|
401
|
+
}
|
402
|
+
if (urls.length == 0) {
|
403
|
+
$.get("/parts/download_form")
|
404
|
+
.done(function(html) {
|
405
|
+
var download_modal = bootbox.dialog({
|
406
|
+
title: "ダウンロードする小説のURL、もしくはNコードを入力(複数可)",
|
407
|
+
message: html,
|
408
|
+
backdrop: true,
|
409
|
+
buttons: {
|
410
|
+
cancel: {
|
411
|
+
label: "キャンセル",
|
412
|
+
className: "btn-default"
|
413
|
+
},
|
414
|
+
main: {
|
415
|
+
label: "ダウンロード",
|
416
|
+
className: "btn-primary",
|
417
|
+
callback: function() {
|
418
|
+
$("#download-link-submit").click();
|
419
|
+
}
|
420
|
+
}
|
421
|
+
}
|
422
|
+
});
|
423
|
+
download_modal.one("shown.bs.modal", function () {
|
424
|
+
$("#download-input").focus();
|
425
|
+
});
|
426
|
+
});
|
427
|
+
}
|
428
|
+
else {
|
429
|
+
$.post("/api/download", { targets: urls });
|
430
|
+
}
|
376
431
|
},
|
377
432
|
|
378
433
|
downloadForce: function() {
|
@@ -529,6 +584,28 @@ var Narou = (function() {
|
|
529
584
|
if (ids.length === 0) return;
|
530
585
|
$.post("/api/setting_burn", { "ids": ids });
|
531
586
|
},
|
587
|
+
|
588
|
+
csvImport: function() {
|
589
|
+
$.get("/parts/csv_import", function(html) {
|
590
|
+
var box = bootbox.dialog({
|
591
|
+
title: "CSVファイルからのインポート",
|
592
|
+
message: html,
|
593
|
+
buttons: {
|
594
|
+
cancel: {
|
595
|
+
label: "キャンセル",
|
596
|
+
className: "btn-default",
|
597
|
+
},
|
598
|
+
main: {
|
599
|
+
label: "インポート",
|
600
|
+
className: "btn-primary",
|
601
|
+
callback: function() {
|
602
|
+
$("#csv-import-files").click();
|
603
|
+
}
|
604
|
+
}
|
605
|
+
}
|
606
|
+
});
|
607
|
+
});
|
608
|
+
},
|
532
609
|
});
|
533
610
|
|
534
611
|
/*************************************************************************
|
@@ -576,6 +653,9 @@ var Narou = (function() {
|
|
576
653
|
$(this.options.buttons_id + " .console-trash").on("click", function(e) {
|
577
654
|
self.trash_console();
|
578
655
|
});
|
656
|
+
$(this.options.buttons_id + " .queue-cancel").on("click", function(e) {
|
657
|
+
$.post("/api/cancel");
|
658
|
+
});
|
579
659
|
},
|
580
660
|
|
581
661
|
init_events: function() {
|
@@ -600,15 +680,14 @@ var Narou = (function() {
|
|
600
680
|
var self = this;
|
601
681
|
var $progress = null;
|
602
682
|
var createProgressHtml = function(percent) {
|
603
|
-
return '<div class="progress"><div class="progress-bar progress-bar-success progress-bar-striped active" role="progressbar"
|
683
|
+
return '<div class="progress"><div class="progress-bar progress-bar-success progress-bar-striped active" role="progressbar" style="width:' + percent + '%"></div></div>';
|
604
684
|
};
|
605
685
|
var initializeProgressbar = function(percent) {
|
606
686
|
self.puts(createProgressHtml(percent));
|
607
687
|
$progress = self.console.find(".progress > div");
|
608
688
|
};
|
609
689
|
var setProgressValue = function(step) {
|
610
|
-
$progress.
|
611
|
-
.width(step + "%");
|
690
|
+
$progress.width(step + "%");
|
612
691
|
};
|
613
692
|
this.notification.on("progressbar.init", function() {
|
614
693
|
initializeProgressbar(0);
|
@@ -623,13 +702,8 @@ var Narou = (function() {
|
|
623
702
|
});
|
624
703
|
this.notification.on("progressbar.clear", function() {
|
625
704
|
if (!$progress) return;
|
626
|
-
// 表示と通信のタイムラグで100%付近のが表示されないまま消えてしまうので、
|
627
|
-
// 演出的にプログレスバーの消去を遅らせて、100%付近まで表示する
|
628
|
-
setProgressValue(100);
|
629
705
|
$progress = null;
|
630
|
-
|
631
|
-
$(".progress").parent("div").remove();
|
632
|
-
}, 500);
|
706
|
+
$(".progress").parent("div").remove();
|
633
707
|
});
|
634
708
|
},
|
635
709
|
|
@@ -740,6 +814,7 @@ var Narou = (function() {
|
|
740
814
|
$.post("/api/clear_history");
|
741
815
|
},
|
742
816
|
|
817
|
+
// コンソールの内容をクリア
|
743
818
|
clear: function() {
|
744
819
|
this.console.find("div.console-line").remove();
|
745
820
|
}
|
@@ -750,13 +825,13 @@ var Narou = (function() {
|
|
750
825
|
*************************************************************************/
|
751
826
|
var Tag = Narou.Tag = (function(table) {
|
752
827
|
this.table = table;
|
828
|
+
this.registerEvents($("#tag-list-canvas"));
|
753
829
|
this.updateCanvas();
|
754
830
|
});
|
755
831
|
|
756
832
|
$.extend(Tag.prototype, {
|
757
833
|
updateCanvas: function() {
|
758
834
|
var $canvas = $("#tag-list-canvas");
|
759
|
-
this.registerEvents($canvas);
|
760
835
|
$.get("/api/tag_list", function(source) {
|
761
836
|
$canvas.html(source);
|
762
837
|
});
|
@@ -773,6 +848,7 @@ var Narou = (function() {
|
|
773
848
|
storage.set("tag_search", tag_name);
|
774
849
|
storage.save();
|
775
850
|
self.table.draw();
|
851
|
+
self.table.$("[data-toggle=tooltip]").tooltip("hide");
|
776
852
|
}).on("mousedown", ".tag", args, function(e) {
|
777
853
|
// 範囲選択モードでもクリック出来るように
|
778
854
|
if (e.data.stop_bubbling) e.stopPropagation();
|
@@ -882,6 +958,162 @@ var Narou = (function() {
|
|
882
958
|
},
|
883
959
|
});
|
884
960
|
|
961
|
+
/*************************************************************************
|
962
|
+
* タグの色選択機能
|
963
|
+
*************************************************************************/
|
964
|
+
var SelectColorMenu = Narou.SelectColorMenu = (function() {
|
965
|
+
this.initializeEvents();
|
966
|
+
this.initializeMenuEvents();
|
967
|
+
this.$menu = $("#select-color-menu");
|
968
|
+
});
|
969
|
+
|
970
|
+
$.extend(SelectColorMenu.prototype, {
|
971
|
+
open: function(target_tag, pos, callback) {
|
972
|
+
var self = this;
|
973
|
+
this.target_tag = target_tag;
|
974
|
+
var caller = function() {
|
975
|
+
if (typeof callback === "function")
|
976
|
+
callback();
|
977
|
+
};
|
978
|
+
$(document).one("hide.bs.dropdown", function() {
|
979
|
+
self.$menu.hide();
|
980
|
+
});
|
981
|
+
Narou.popupMenu("#select-color-menu", pos, function() {
|
982
|
+
self.$menu.hide();
|
983
|
+
caller();
|
984
|
+
});
|
985
|
+
},
|
986
|
+
|
987
|
+
initializeEvents: function() {
|
988
|
+
var self = this;
|
989
|
+
$(document).on("click", ".select-color-button", function(e) {
|
990
|
+
e.stopPropagation();
|
991
|
+
var $this = $(this);
|
992
|
+
var pos = {
|
993
|
+
x: $this.offset().left + $this.width() + 10,
|
994
|
+
y: $this.offset().top - 20
|
995
|
+
}
|
996
|
+
self.open($(this).data("targetTag"), pos, function() {
|
997
|
+
});
|
998
|
+
});
|
999
|
+
},
|
1000
|
+
|
1001
|
+
initializeMenuEvents: function() {
|
1002
|
+
var self = this;
|
1003
|
+
var colors = ["green", "yellow", "blue", "magenta", "cyan", "red", "white"];
|
1004
|
+
$.each(colors, function(i, color) {
|
1005
|
+
$("#select-color-menu-" + color).on("click", function(e) {
|
1006
|
+
e.preventDefault();
|
1007
|
+
e.stopPropagation();
|
1008
|
+
$.post("/api/change_tag_color", {
|
1009
|
+
tag: self.target_tag,
|
1010
|
+
color: color
|
1011
|
+
});
|
1012
|
+
self.$menu.hide();
|
1013
|
+
});
|
1014
|
+
});
|
1015
|
+
},
|
1016
|
+
});
|
1017
|
+
|
1018
|
+
/*************************************************************************
|
1019
|
+
* ドラッグ&ドロップ関係
|
1020
|
+
*************************************************************************/
|
1021
|
+
var DragDrop = Narou.DragDrop = (function() {
|
1022
|
+
this.initializeValidateUrlRegexpList();
|
1023
|
+
});
|
1024
|
+
|
1025
|
+
$.extend(DragDrop.prototype, {
|
1026
|
+
initializeValidateUrlRegexpList: function() {
|
1027
|
+
if (typeof this.validate_url_regexp_list !== "undefined") return;
|
1028
|
+
var self = this;
|
1029
|
+
this.validate_url_regexp_list = [];
|
1030
|
+
$.ajax({
|
1031
|
+
type: "GET",
|
1032
|
+
url: "/api/validate_url_regexp_list",
|
1033
|
+
dataType: "json",
|
1034
|
+
success: function(json) {
|
1035
|
+
$.each(json, function(i, value) {
|
1036
|
+
self.validate_url_regexp_list.push(value);
|
1037
|
+
});
|
1038
|
+
}
|
1039
|
+
});
|
1040
|
+
},
|
1041
|
+
|
1042
|
+
isValidNovelUrl: function(url) {
|
1043
|
+
var result = false;
|
1044
|
+
$.each(this.validate_url_regexp_list, function(i, regexp) {
|
1045
|
+
if (url.match(regexp)) {
|
1046
|
+
result = true;
|
1047
|
+
return false; // break
|
1048
|
+
}
|
1049
|
+
});
|
1050
|
+
return result;
|
1051
|
+
},
|
1052
|
+
|
1053
|
+
getLinkText: function(event, callback) {
|
1054
|
+
var self = this;
|
1055
|
+
var data_transfer = event.dataTransfer;
|
1056
|
+
$.each(data_transfer.types, function(i, type) {
|
1057
|
+
if (type === "Files") {
|
1058
|
+
// ショートカットファイルがドラッグされた場合は中身からリンクを抜き出す
|
1059
|
+
$.each(data_transfer.files, function(i, file) {
|
1060
|
+
if (!self.isSupportFile(file.name)) return;
|
1061
|
+
var reader = new FileReader;
|
1062
|
+
reader.onload = function(e) {
|
1063
|
+
var link = self.parseLink(file.name, reader.result);
|
1064
|
+
if (link) callback(link);
|
1065
|
+
};
|
1066
|
+
reader.readAsText(file);
|
1067
|
+
});
|
1068
|
+
}
|
1069
|
+
else {
|
1070
|
+
// TextはIE用
|
1071
|
+
if (type === "text/plain" || type === "Text") {
|
1072
|
+
var link = data_transfer.getData(type);
|
1073
|
+
if (link.length > 0) {
|
1074
|
+
callback(link);
|
1075
|
+
}
|
1076
|
+
}
|
1077
|
+
}
|
1078
|
+
});
|
1079
|
+
return;
|
1080
|
+
},
|
1081
|
+
|
1082
|
+
isSupportFile: function(filename) {
|
1083
|
+
return !!filename.match(/\.(?:url|webloc)$/i);
|
1084
|
+
},
|
1085
|
+
|
1086
|
+
parseLink: function(filename, text) {
|
1087
|
+
filename.toLowerCase().match(/\.(url|webloc)$/);
|
1088
|
+
var link = null;
|
1089
|
+
switch (RegExp.$1) {
|
1090
|
+
case "url":
|
1091
|
+
link = this.parseLinkDotURL(text);
|
1092
|
+
break;
|
1093
|
+
case "webloc":
|
1094
|
+
link = this.parseLinkDotWebloc(text);
|
1095
|
+
break;
|
1096
|
+
}
|
1097
|
+
return link;
|
1098
|
+
},
|
1099
|
+
|
1100
|
+
// OSX で使われる .webloc 形式のショートカット
|
1101
|
+
parseLinkDotWebloc: function(text) {
|
1102
|
+
if (text.match(/<string>(.+?)<\/string>/i)) {
|
1103
|
+
return RegExp.$1;
|
1104
|
+
}
|
1105
|
+
return null;
|
1106
|
+
},
|
1107
|
+
|
1108
|
+
// Windows で使われる .URL 形式のショートカット
|
1109
|
+
parseLinkDotURL: function(text) {
|
1110
|
+
if (text.match(/URL=(.+)/i)) {
|
1111
|
+
return RegExp.$1;
|
1112
|
+
}
|
1113
|
+
return null;
|
1114
|
+
},
|
1115
|
+
});
|
1116
|
+
|
885
1117
|
return Narou;
|
886
1118
|
})();
|
887
1119
|
|