1 /*
2 ** jquery.schedule.js -- jQuery plugin for scheduled/deferred actions
3 ** Copyright (c) 2007 Ralf S. Engelschall <rse@engelschall.com>
4 ** Licensed under GPL <http://www.gnu.org/licenses/gpl.txt>
5 **
6 ** $LastChangedDate$
7 ** $LastChangedRevision$
8 */
9
10 /*
11 * <div id="button">TEST BUTTON</div>
12 * <div id="test"></div>
13 *
14 * <script type="text/javascript">
15 * $(document).ready(
16 * function(){
17 * $('#button').click(function () {
18 * $(this).css("color", "blue").schedule(2000, function (x) {
19 * $(this).css("color", "red");
20 * $("#test").html("test: x = " + x);
21 * }, 42);
22 * });
23 * });
24 * </script>
25 */
26
27 (function($) {
28
29 /* object constructor */
30 $.scheduler = function () {
31 this.bucket = {};
32 return;
33 };
34
35 /* object methods */
36 $.scheduler.prototype = {
37 /* schedule a task */
38 schedule: function () {
39 /* schedule context with default parameters */
40 var ctx = {
41 "id": null, /* unique identifier of high-level schedule */
42 "time": 1000, /* time in milliseconds after which the task is run */
43 "repeat": false, /* whether schedule should be automatically repeated */
44 "protect": false, /* whether schedule should be protected from double scheduling */
45 "obj": null, /* function context object ("this") */
46 "func": function(){}, /* function to call */
47 "args": [] /* function arguments to pass */
48 };
49
50 /* helper function: portable checking whether something is a function */
51 function _isfn (fn) {
52 return (
53 !!fn
54 && typeof fn != "string"
55 && typeof fn[0] == "undefined"
56 && RegExp("function", "i").test(fn + "")
57 );
58 };
59
60 /* parse arguments into context parameters (part 1/4):
61 detect an override object (special case to support jQuery method) */
62 var i = 0;
63 var override = false;
64 if (typeof arguments[i] == "object" && arguments.length > 1) {
65 override = true;
66 i++;
67 }
68
69 /* parse arguments into context parameters (part 2/4):
70 support the flexible way of an associated array */
71 if (typeof arguments[i] == "object") {
72 for (var option in arguments[i])
73 if (typeof ctx[option] != "undefined")
74 ctx[option] = arguments[i][option];
75 i++;
76 }
77
78 /* parse arguments into context parameters (part 3/4):
79 support: schedule([time [, repeat], ]{{obj, methodname} | func}[, arg, ...]); */
80 if ( typeof arguments[i] == "number"
81 || ( typeof arguments[i] == "string"
82 && arguments[i].match(RegExp("^[0-9]+[smhdw]$"))))
83 ctx["time"] = arguments[i++];
84 if (typeof arguments[i] == "boolean")
85 ctx["repeat"] = arguments[i++];
86 if (typeof arguments[i] == "boolean")
87 ctx["protect"] = arguments[i++];
88 if ( typeof arguments[i] == "object"
89 && typeof arguments[i+1] == "string"
90 && _isfn(arguments[i][arguments[i+1]])) {
91 ctx["obj"] = arguments[i++];
92 ctx["func"] = arguments[i++];
93 }
94 else if ( typeof arguments[i] != "undefined"
95 && ( _isfn(arguments[i])
96 || typeof arguments[i] == "string"))
97 ctx["func"] = arguments[i++];
98 while (typeof arguments[i] != "undefined")
99 ctx["args"].push(arguments[i++]);
100
101 /* parse arguments into context parameters (part 4/4):
102 apply parameters from override object */
103 if (override) {
104 if (typeof arguments[1] == "object") {
105 for (var option in arguments[0])
106 if ( typeof ctx[option] != "undefined"
107 && typeof arguments[1][option] == "undefined")
108 ctx[option] = arguments[0][option];
109 }
110 else {
111 for (var option in arguments[0])
112 if (typeof ctx[option] != "undefined")
113 ctx[option] = arguments[0][option];
114 }
115 i++;
116 }
117
118 /* annotate context with internals */
119 ctx["_scheduler"] = this; /* internal: back-reference to scheduler object */
120 ctx["_handle"] = null; /* internal: unique handle of low-level task */
121
122 /* determine time value in milliseconds */
123 var match = String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$"));
124 if (match && match[0] != "undefined" && match[1] != "undefined")
125 ctx["time"] = String(parseInt(match[1]) *
126 { s: 1000, m: 1000*60, h: 1000*60*60,
127 d: 1000*60*60*24, w: 1000*60*60*24*7 }[match[2]]);
128
129 /* determine unique identifier of task */
130 if (ctx["id"] == null)
131 ctx["id"] = ( String(ctx["repeat"]) + ":"
132 + String(ctx["protect"]) + ":"
133 + String(ctx["time"]) + ":"
134 + String(ctx["obj"]) + ":"
135 + String(ctx["func"]) + ":"
136 + String(ctx["args"]) );
137
138 /* optionally protect from duplicate calls */
139 if (ctx["protect"])
140 if (typeof this.bucket[ctx["id"]] != "undefined")
141 return this.bucket[ctx["id"]];
142
143 /* support execution of methods by name and arbitrary scripts */
144 if (!_isfn(ctx["func"])) {
145 if ( ctx["obj"] != null
146 && typeof ctx["obj"] == "object"
147 && typeof ctx["func"] == "string"
148 && _isfn(ctx["obj"][ctx["func"]]))
149 /* method by name */
150 ctx["func"] = ctx["obj"][ctx["func"]];
151 else
152 /* arbitrary script */
153 ctx["func"] = eval("function () { " + ctx["func"] + " }");
154 }
155
156 /* pass-through to internal scheduling operation */
157 ctx["_handle"] = this._schedule(ctx);
158
159 /* store context into bucket of scheduler object */
160 this.bucket[ctx["id"]] = ctx;
161
162 /* return context */
163 return ctx;
164 },
165
166 /* re-schedule a task */
167 reschedule: function (ctx) {
168 if (typeof ctx == "string")
169 ctx = this.bucket[ctx];
170
171 /* pass-through to internal scheduling operation */
172 ctx["_handle"] = this._schedule(ctx);
173
174 /* return context */
175 return ctx;
176 },
177
178 /* internal scheduling operation */
179 _schedule: function (ctx) {
180 /* closure to act as the call trampoline function */
181 var trampoline = function () {
182 /* jump into function */
183 var obj = (ctx["obj"] != null ? ctx["obj"] : ctx);
184 (ctx["func"]).apply(obj, ctx["args"]);
185
186 /* either repeat scheduling and keep in bucket or
187 just stop scheduling and delete from scheduler bucket */
188 if ( /* not cancelled from inside... */
189 typeof (ctx["_scheduler"]).bucket[ctx["id"]] != "undefined"
190 && /* ...and repeating requested */
191 ctx["repeat"])
192 (ctx["_scheduler"])._schedule(ctx);
193 else
194 delete (ctx["_scheduler"]).bucket[ctx["id"]];
195 };
196
197 /* schedule task and return handle */
198 return setTimeout(trampoline, ctx["time"]);
199 },
200
201 /* cancel a scheduled task */
202 cancel: function (ctx) {
203 if (typeof ctx == "string")
204 ctx = this.bucket[ctx];
205
206 /* cancel scheduled task */
207 if (typeof ctx == "object") {
208 clearTimeout(ctx["_handle"]);
209 delete this.bucket[ctx["id"]];
210 }
211 }
212 };
213
214 /* integrate a global instance of the scheduler into the global jQuery object */
215 $.extend({
216 scheduler$: new $.scheduler(),
217 schedule: function () { return $.scheduler$.schedule.apply ($.scheduler$, arguments) },
218 reschedule: function () { return $.scheduler$.reschedule.apply($.scheduler$, arguments) },
219 cancel: function () { return $.scheduler$.cancel.apply ($.scheduler$, arguments) }
220 });
221
222 /* integrate scheduling convinience method into all jQuery objects */
223 $.fn.extend({
224 schedule: function () {
225 var a = [ {} ];
226 for (var i = 0; i < arguments.length; i++)
227 a.push(arguments[i]);
228 return this.each(function () {
229 a[0] = { "id": this, "obj": this };
230 return $.schedule.apply($, a);
231 });
232 }
233 });
234
235 })(jQuery);
236
237 /*
238 ** jquery.schedule.js -- jQuery plugin for scheduled/deferred actions
239 ** Copyright (c) 2007 Ralf S. Engelschall <rse@engelschall.com>
240 ** Licensed under GPL <http://www.gnu.org/licenses/gpl.txt>
241 **
242 ** $LastChangedDate$
243 ** $LastChangedRevision$
244 */
245
246 /*
247 * <div id="button">TEST BUTTON</div>
248 * <div id="test"></div>
249 *
250 * <script type="text/javascript">
251 * $(document).ready(
252 * function(){
253 * $('#button').click(function () {
254 * $(this).css("color", "blue").schedule(2000, function (x) {
255 * $(this).css("color", "red");
256 * $("#test").html("test: x = " + x);
257 * }, 42);
258 * });
259 * });
260 * </script>
261 */
262
263 (function($) {
264
265 /* object constructor */
266 $.scheduler = function () {
267 this.bucket = {};
268 return;
269 };
270
271 /* object methods */
272 $.scheduler.prototype = {
273 /* schedule a task */
274 schedule: function () {
275 /* schedule context with default parameters */
276 var ctx = {
277 "id": null, /* unique identifier of high-level schedule */
278 "time": 1000, /* time in milliseconds after which the task is run */
279 "repeat": false, /* whether schedule should be automatically repeated */
280 "protect": false, /* whether schedule should be protected from double scheduling */
281 "obj": null, /* function context object ("this") */
282 "func": function(){}, /* function to call */
283 "args": [] /* function arguments to pass */
284 };
285
286 /* helper function: portable checking whether something is a function */
287 function _isfn (fn) {
288 return (
289 !!fn
290 && typeof fn != "string"
291 && typeof fn[0] == "undefined"
292 && RegExp("function", "i").test(fn + "")
293 );
294 };
295
296 /* parse arguments into context parameters (part 1/4):
297 detect an override object (special case to support jQuery method) */
298 var i = 0;
299 var override = false;
300 if (typeof arguments[i] == "object" && arguments.length > 1) {
301 override = true;
302 i++;
303 }
304
305 /* parse arguments into context parameters (part 2/4):
306 support the flexible way of an associated array */
307 if (typeof arguments[i] == "object") {
308 for (var option in arguments[i])
309 if (typeof ctx[option] != "undefined")
310 ctx[option] = arguments[i][option];
311 i++;
312 }
313
314 /* parse arguments into context parameters (part 3/4):
315 support: schedule([time [, repeat], ]{{obj, methodname} | func}[, arg, ...]); */
316 if ( typeof arguments[i] == "number"
317 || ( typeof arguments[i] == "string"
318 && arguments[i].match(RegExp("^[0-9]+[smhdw]$"))))
319 ctx["time"] = arguments[i++];
320 if (typeof arguments[i] == "boolean")
321 ctx["repeat"] = arguments[i++];
322 if (typeof arguments[i] == "boolean")
323 ctx["protect"] = arguments[i++];
324 if ( typeof arguments[i] == "object"
325 && typeof arguments[i+1] == "string"
326 && _isfn(arguments[i][arguments[i+1]])) {
327 ctx["obj"] = arguments[i++];
328 ctx["func"] = arguments[i++];
329 }
330 else if ( typeof arguments[i] != "undefined"
331 && ( _isfn(arguments[i])
332 || typeof arguments[i] == "string"))
333 ctx["func"] = arguments[i++];
334 while (typeof arguments[i] != "undefined")
335 ctx["args"].push(arguments[i++]);
336
337 /* parse arguments into context parameters (part 4/4):
338 apply parameters from override object */
339 if (override) {
340 if (typeof arguments[1] == "object") {
341 for (var option in arguments[0])
342 if ( typeof ctx[option] != "undefined"
343 && typeof arguments[1][option] == "undefined")
344 ctx[option] = arguments[0][option];
345 }
346 else {
347 for (var option in arguments[0])
348 if (typeof ctx[option] != "undefined")
349 ctx[option] = arguments[0][option];
350 }
351 i++;
352 }
353
354 /* annotate context with internals */
355 ctx["_scheduler"] = this; /* internal: back-reference to scheduler object */
356 ctx["_handle"] = null; /* internal: unique handle of low-level task */
357
358 /* determine time value in milliseconds */
359 var match = String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$"));
360 if (match && match[0] != "undefined" && match[1] != "undefined")
361 ctx["time"] = String(parseInt(match[1]) *
362 { s: 1000, m: 1000*60, h: 1000*60*60,
363 d: 1000*60*60*24, w: 1000*60*60*24*7 }[match[2]]);
364
365 /* determine unique identifier of task */
366 if (ctx["id"] == null)
367 ctx["id"] = ( String(ctx["repeat"]) + ":"
368 + String(ctx["protect"]) + ":"
369 + String(ctx["time"]) + ":"
370 + String(ctx["obj"]) + ":"
371 + String(ctx["func"]) + ":"
372 + String(ctx["args"]) );
373
374 /* optionally protect from duplicate calls */
375 if (ctx["protect"])
376 if (typeof this.bucket[ctx["id"]] != "undefined")
377 return this.bucket[ctx["id"]];
378
379 /* support execution of methods by name and arbitrary scripts */
380 if (!_isfn(ctx["func"])) {
381 if ( ctx["obj"] != null
382 && typeof ctx["obj"] == "object"
383 && typeof ctx["func"] == "string"
384 && _isfn(ctx["obj"][ctx["func"]]))
385 /* method by name */
386 ctx["func"] = ctx["obj"][ctx["func"]];
387 else
388 /* arbitrary script */
389 ctx["func"] = eval("function () { " + ctx["func"] + " }");
390 }
391
392 /* pass-through to internal scheduling operation */
393 ctx["_handle"] = this._schedule(ctx);
394
395 /* store context into bucket of scheduler object */
396 this.bucket[ctx["id"]] = ctx;
397
398 /* return context */
399 return ctx;
400 },
401
402 /* re-schedule a task */
403 reschedule: function (ctx) {
404 if (typeof ctx == "string")
405 ctx = this.bucket[ctx];
406
407 /* pass-through to internal scheduling operation */
408 ctx["_handle"] = this._schedule(ctx);
409
410 /* return context */
411 return ctx;
412 },
413
414 /* internal scheduling operation */
415 _schedule: function (ctx) {
416 /* closure to act as the call trampoline function */
417 var trampoline = function () {
418 /* jump into function */
419 var obj = (ctx["obj"] != null ? ctx["obj"] : ctx);
420 (ctx["func"]).apply(obj, ctx["args"]);
421
422 /* either repeat scheduling and keep in bucket or
423 just stop scheduling and delete from scheduler bucket */
424 if ( /* not cancelled from inside... */
425 typeof (ctx["_scheduler"]).bucket[ctx["id"]] != "undefined"
426 && /* ...and repeating requested */
427 ctx["repeat"])
428 (ctx["_scheduler"])._schedule(ctx);
429 else
430 delete (ctx["_scheduler"]).bucket[ctx["id"]];
431 };
432
433 /* schedule task and return handle */
434 return setTimeout(trampoline, ctx["time"]);
435 },
436
437 /* cancel a scheduled task */
438 cancel: function (ctx) {
439 if (typeof ctx == "string")
440 ctx = this.bucket[ctx];
441
442 /* cancel scheduled task */
443 if (typeof ctx == "object") {
444 clearTimeout(ctx["_handle"]);
445 delete this.bucket[ctx["id"]];
446 }
447 }
448 };
449
450 /* integrate a global instance of the scheduler into the global jQuery object */
451 $.extend({
452 scheduler$: new $.scheduler(),
453 schedule: function () { return $.scheduler$.schedule.apply ($.scheduler$, arguments) },
454 reschedule: function () { return $.scheduler$.reschedule.apply($.scheduler$, arguments) },
455 cancel: function () { return $.scheduler$.cancel.apply ($.scheduler$, arguments) }
456 });
457
458 /* integrate scheduling convinience method into all jQuery objects */
459 $.fn.extend({
460 schedule: function () {
461 var a = [ {} ];
462 for (var i = 0; i < arguments.length; i++)
463 a.push(arguments[i]);
464 return this.each(function () {
465 a[0] = { "id": this, "obj": this };
466 return $.schedule.apply($, a);
467 });
468 }
469 });
470
471 })(jQuery);
472
473 /*
474 ** jquery.schedule.js -- jQuery plugin for scheduled/deferred actions
475 ** Copyright (c) 2007 Ralf S. Engelschall <rse@engelschall.com>
476 ** Licensed under GPL <http://www.gnu.org/licenses/gpl.txt>
477 **
478 ** $LastChangedDate$
479 ** $LastChangedRevision$
480 */
481
482 /*
483 * <div id="button">TEST BUTTON</div>
484 * <div id="test"></div>
485 *
486 * <script type="text/javascript">
487 * $(document).ready(
488 * function(){
489 * $('#button').click(function () {
490 * $(this).css("color", "blue").schedule(2000, function (x) {
491 * $(this).css("color", "red");
492 * $("#test").html("test: x = " + x);
493 * }, 42);
494 * });
495 * });
496 * </script>
497 */
498
499 (function($) {
500
501 /* object constructor */
502 $.scheduler = function () {
503 this.bucket = {};
504 return;
505 };
506
507 /* object methods */
508 $.scheduler.prototype = {
509 /* schedule a task */
510 schedule: function () {
511 /* schedule context with default parameters */
512 var ctx = {
513 "id": null, /* unique identifier of high-level schedule */
514 "time": 1000, /* time in milliseconds after which the task is run */
515 "repeat": false, /* whether schedule should be automatically repeated */
516 "protect": false, /* whether schedule should be protected from double scheduling */
517 "obj": null, /* function context object ("this") */
518 "func": function(){}, /* function to call */
519 "args": [] /* function arguments to pass */
520 };
521
522 /* helper function: portable checking whether something is a function */
523 function _isfn (fn) {
524 return (
525 !!fn
526 && typeof fn != "string"
527 && typeof fn[0] == "undefined"
528 && RegExp("function", "i").test(fn + "")
529 );
530 };
531
532 /* parse arguments into context parameters (part 1/4):
533 detect an override object (special case to support jQuery method) */
534 var i = 0;
535 var override = false;
536 if (typeof arguments[i] == "object" && arguments.length > 1) {
537 override = true;
538 i++;
539 }
540
541 /* parse arguments into context parameters (part 2/4):
542 support the flexible way of an associated array */
543 if (typeof arguments[i] == "object") {
544 for (var option in arguments[i])
545 if (typeof ctx[option] != "undefined")
546 ctx[option] = arguments[i][option];
547 i++;
548 }
549
550 /* parse arguments into context parameters (part 3/4):
551 support: schedule([time [, repeat], ]{{obj, methodname} | func}[, arg, ...]); */
552 if ( typeof arguments[i] == "number"
553 || ( typeof arguments[i] == "string"
554 && arguments[i].match(RegExp("^[0-9]+[smhdw]$"))))
555 ctx["time"] = arguments[i++];
556 if (typeof arguments[i] == "boolean")
557 ctx["repeat"] = arguments[i++];
558 if (typeof arguments[i] == "boolean")
559 ctx["protect"] = arguments[i++];
560 if ( typeof arguments[i] == "object"
561 && typeof arguments[i+1] == "string"
562 && _isfn(arguments[i][arguments[i+1]])) {
563 ctx["obj"] = arguments[i++];
564 ctx["func"] = arguments[i++];
565 }
566 else if ( typeof arguments[i] != "undefined"
567 && ( _isfn(arguments[i])
568 || typeof arguments[i] == "string"))
569 ctx["func"] = arguments[i++];
570 while (typeof arguments[i] != "undefined")
571 ctx["args"].push(arguments[i++]);
572
573 /* parse arguments into context parameters (part 4/4):
574 apply parameters from override object */
575 if (override) {
576 if (typeof arguments[1] == "object") {
577 for (var option in arguments[0])
578 if ( typeof ctx[option] != "undefined"
579 && typeof arguments[1][option] == "undefined")
580 ctx[option] = arguments[0][option];
581 }
582 else {
583 for (var option in arguments[0])
584 if (typeof ctx[option] != "undefined")
585 ctx[option] = arguments[0][option];
586 }
587 i++;
588 }
589
590 /* annotate context with internals */
591 ctx["_scheduler"] = this; /* internal: back-reference to scheduler object */
592 ctx["_handle"] = null; /* internal: unique handle of low-level task */
593
594 /* determine time value in milliseconds */
595 var match = String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$"));
596 if (match && match[0] != "undefined" && match[1] != "undefined")
597 ctx["time"] = String(parseInt(match[1]) *
598 { s: 1000, m: 1000*60, h: 1000*60*60,
599 d: 1000*60*60*24, w: 1000*60*60*24*7 }[match[2]]);
600
601 /* determine unique identifier of task */
602 if (ctx["id"] == null)
603 ctx["id"] = ( String(ctx["repeat"]) + ":"
604 + String(ctx["protect"]) + ":"
605 + String(ctx["time"]) + ":"
606 + String(ctx["obj"]) + ":"
607 + String(ctx["func"]) + ":"
608 + String(ctx["args"]) );
609
610 /* optionally protect from duplicate calls */
611 if (ctx["protect"])
612 if (typeof this.bucket[ctx["id"]] != "undefined")
613 return this.bucket[ctx["id"]];
614
615 /* support execution of methods by name and arbitrary scripts */
616 if (!_isfn(ctx["func"])) {
617 if ( ctx["obj"] != null
618 && typeof ctx["obj"] == "object"
619 && typeof ctx["func"] == "string"
620 && _isfn(ctx["obj"][ctx["func"]]))
621 /* method by name */
622 ctx["func"] = ctx["obj"][ctx["func"]];
623 else
624 /* arbitrary script */
625 ctx["func"] = eval("function () { " + ctx["func"] + " }");
626 }
627
628 /* pass-through to internal scheduling operation */
629 ctx["_handle"] = this._schedule(ctx);
630
631 /* store context into bucket of scheduler object */
632 this.bucket[ctx["id"]] = ctx;
633
634 /* return context */
635 return ctx;
636 },
637
638 /* re-schedule a task */
639 reschedule: function (ctx) {
640 if (typeof ctx == "string")
641 ctx = this.bucket[ctx];
642
643 /* pass-through to internal scheduling operation */
644 ctx["_handle"] = this._schedule(ctx);
645
646 /* return context */
647 return ctx;
648 },
649
650 /* internal scheduling operation */
651 _schedule: function (ctx) {
652 /* closure to act as the call trampoline function */
653 var trampoline = function () {
654 /* jump into function */
655 var obj = (ctx["obj"] != null ? ctx["obj"] : ctx);
656 (ctx["func"]).apply(obj, ctx["args"]);
657
658 /* either repeat scheduling and keep in bucket or
659 just stop scheduling and delete from scheduler bucket */
660 if ( /* not cancelled from inside... */
661 typeof (ctx["_scheduler"]).bucket[ctx["id"]] != "undefined"
662 && /* ...and repeating requested */
663 ctx["repeat"])
664 (ctx["_scheduler"])._schedule(ctx);
665 else
666 delete (ctx["_scheduler"]).bucket[ctx["id"]];
667 };
668
669 /* schedule task and return handle */
670 return setTimeout(trampoline, ctx["time"]);
671 },
672
673 /* cancel a scheduled task */
674 cancel: function (ctx) {
675 if (typeof ctx == "string")
676 ctx = this.bucket[ctx];
677
678 /* cancel scheduled task */
679 if (typeof ctx == "object") {
680 clearTimeout(ctx["_handle"]);
681 delete this.bucket[ctx["id"]];
682 }
683 }
684 };
685
686 /* integrate a global instance of the scheduler into the global jQuery object */
687 $.extend({
688 scheduler$: new $.scheduler(),
689 schedule: function () { return $.scheduler$.schedule.apply ($.scheduler$, arguments) },
690 reschedule: function () { return $.scheduler$.reschedule.apply($.scheduler$, arguments) },
691 cancel: function () { return $.scheduler$.cancel.apply ($.scheduler$, arguments) }
692 });
693
694 /* integrate scheduling convinience method into all jQuery objects */
695 $.fn.extend({
696 schedule: function () {
697 var a = [ {} ];
698 for (var i = 0; i < arguments.length; i++)
699 a.push(arguments[i]);
700 return this.each(function () {
701 a[0] = { "id": this, "obj": this };
702 return $.schedule.apply($, a);
703 });
704 }
705 });
706
707 })(jQuery);
708
お問い合わせ |
---|
記事が読めない?無料でお答えします!個人サイト、中小企業サイトのための無料ヘルプ! |
① 電話:020-2206-9892 |
② QQ咨询:1025174874 |
三 Eメール:info@361sale.com |
④ 勤務時間: 月~金、9:30~18:30、祝日休み |
© 複製に関する声明
この記事はハリーが執筆しました。
この記事へのリンクhttps://www.361sale.com/ja/12526この記事は著作権で保護されており、必ず帰属表示を付けて複製してください。
終わり
コメントなし