Added views for QOR admin
This commit is contained in:
21
app/views/qor/action.tmpl
Normal file
21
app/views/qor/action.tmpl
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{{$action := .Result}}
|
||||||
|
|
||||||
|
<div class="qor-page__body qor-page__edit">
|
||||||
|
{{render "shared/flashes"}}
|
||||||
|
{{render "shared/errors"}}
|
||||||
|
|
||||||
|
<div class="qor-form-container" data-toggle="qor-action-slideout">
|
||||||
|
<form action="{{.Context.Request.URL}}" method="POST" enctype="multipart/form-data">
|
||||||
|
<input name="_method" value="PUT" type="hidden">
|
||||||
|
|
||||||
|
{{if $action.Resource}}
|
||||||
|
{{render_form $action.Resource.NewStruct (edit_sections $action.Resource)}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div class="qor-form__actions" style="margin-top: 0;margin-bottom:10px;">
|
||||||
|
<button class="mdl-button mdl-button--colored mdl-button--raised mdl-js-button mdl-js-ripple-effect qor-button--save" type="submit">{{t "qor_admin.form.submit" "Submit"}}</button>
|
||||||
|
<a class="mdl-button mdl-button--primary mdl-js-button mdl-js-ripple-effect qor-button--cancel" href="javascript:history.back();">{{t "qor_admin.form.cancel" "Cancel"}}</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
12
app/views/qor/actions/9.action.tmpl
Normal file
12
app/views/qor/actions/9.action.tmpl
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{{$context := .}}
|
||||||
|
{{$result := .Result}}
|
||||||
|
{{$allowed_actions := (allowed_actions $context.Resource.GetActions $context.Action $result)}}
|
||||||
|
{{$resource := .Resource}}
|
||||||
|
|
||||||
|
{{if gt (len $allowed_actions) 0 }}
|
||||||
|
<div class="qor-action-forms" data-toggle="qor.action.bulk">
|
||||||
|
{{range $action := $allowed_actions}}
|
||||||
|
{{render_with "shared/action_item" (to_map "Action" $action "Result" $result "Context" $context "Resource" $resource)}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
3
app/views/qor/actions/header/1.page_title.tmpl
Normal file
3
app/views/qor/actions/header/1.page_title.tmpl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<span class="mdl-layout-title">{{page_title}}</span>
|
||||||
|
|
||||||
|
|
||||||
4
app/views/qor/actions/header/5.userinfo.tmpl
Normal file
4
app/views/qor/actions/header/5.userinfo.tmpl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{{if .CurrentUser}}
|
||||||
|
<div class="mdl-layout-spacer"></div>
|
||||||
|
<button class="mdl-button mdl-navigation mdl-layout--small-screen-only qor-mobile--show-actions">{{t "qor_admin.layout.header.actions" "Actions"}} <i class="material-icons">arrow_drop_down</i></button>
|
||||||
|
{{end}}
|
||||||
27
app/views/qor/actions/header/6.searchbar.tmpl
Normal file
27
app/views/qor/actions/header/6.searchbar.tmpl
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{{if .Resource}}
|
||||||
|
{{if .Resource.SearchHandler}}
|
||||||
|
{{ $keyword := .Context.Request.URL.Query.Get "keyword" }}
|
||||||
|
<form class="qor-search-container ignore-dirtyform" method="GET">
|
||||||
|
{{range $key, $values := .Context.Request.URL.Query}}
|
||||||
|
{{if (and (ne $key "keyword") (ne $key "page"))}}
|
||||||
|
{{range $value := $values}}
|
||||||
|
<input name="{{$key}}" value="{{$value}}" type="hidden">
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div class="mdl-textfield mdl-js-textfield mdl-textfield--expandable qor-search">
|
||||||
|
<label class="mdl-button mdl-js-button mdl-button--icon qor-search__label" for="inputSearch">
|
||||||
|
<i class="material-icons">search</i>
|
||||||
|
</label>
|
||||||
|
<div class="mdl-textfield__expandable-holder">
|
||||||
|
<input class="mdl-textfield__input qor-search__input" type="text" id="inputSearch" name="keyword" value="{{ $keyword }}" placeholder="{{t "qor_admin.actions.search_bar_search" "Search"}}">
|
||||||
|
<label class="mdl-textfield__label"></label>
|
||||||
|
</div>
|
||||||
|
<button class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored qor-search__clear" type="button">
|
||||||
|
<i class="material-icons md-18">clear</i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
19
app/views/qor/actions/index/5.scope.tmpl
Normal file
19
app/views/qor/actions/index/5.scope.tmpl
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{{$scopes := get_scopes}}
|
||||||
|
{{$resource := .Resource}}
|
||||||
|
{{if $scopes}}
|
||||||
|
<div class="qor-actions qor-bottomsheet__filter" data-toggle="qor.filter">
|
||||||
|
{{range $scope := $scopes}}
|
||||||
|
{{if $scope.Group}}
|
||||||
|
<select class="qor-action--select" data-toggle="qor.selector" data-clearable="true" name="scopes" placeholder="{{t (printf "%v.scopes.%v" $resource.ToParam $scope.Group) $scope.Group}}">
|
||||||
|
{{range $s := $scope.Scopes}}
|
||||||
|
<option value="{{$s.Name}}" {{if $s.Active}}selected{{end}}>{{t (printf "%v.scopes.%v.%v" $resource.ToParam $scope.Group $s.Label) $s.Label}}</option>
|
||||||
|
{{end}}
|
||||||
|
</select>
|
||||||
|
{{else}}
|
||||||
|
{{range $s := $scope.Scopes}}
|
||||||
|
<a class="qor-action--label {{if $s.Active}}is-active{{end}}" href="{{patch_current_url "scopes" $s.Name}}">{{t (printf "%v.scopes.%v" $resource.ToParam $s.Label) $s.Label}} {{if $s.Active}}<i class="material-icons">clear</i>{{end}}</a>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
28
app/views/qor/actions/index/9.action.tmpl
Normal file
28
app/views/qor/actions/index/9.action.tmpl
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{{$context := .}}
|
||||||
|
{{$result := .Result}}
|
||||||
|
{{$allowed_actions := (allowed_actions $context.Resource.GetActions "batch")}}
|
||||||
|
{{$resource := .Resource}}
|
||||||
|
|
||||||
|
{{if gt (len $allowed_actions) 0 }}
|
||||||
|
<div class="qor-action-bulk-edit" data-toggle="qor.action.bulk">
|
||||||
|
<div class="qor-action-forms" style="display: none;">
|
||||||
|
{{range $action := $allowed_actions}}
|
||||||
|
{{render_with "shared/action_item" (to_map "Action" $action "Result" $result "Context" $context "Resource" $resource "BulkEdit" true)}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="qor-action-bulk-buttons">
|
||||||
|
<button class="mdl-button mdl-button--colored qor-action--bulk" type="button">{{t "qor_admin.actions.bulk_edit" "Bulk Edit"}}</button>
|
||||||
|
<button class="mdl-button mdl-button--accent qor-action--exit-bulk hidden" type="button">{{t "qor_admin.actions.exit_bulk_edit" "Exit Bulk Edit"}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{$collection_actions := (allowed_actions $context.Resource.GetActions "collection")}}
|
||||||
|
{{if gt (len $collection_actions) 0 }}
|
||||||
|
<div class="qor-actions qor-collection-actions" style="float: right">
|
||||||
|
{{range $action := $collection_actions}}
|
||||||
|
{{render_with "shared/action_item" (to_map "Action" $action "Result" $result "Context" $context "Resource" $resource "Multiple" true)}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
41
app/views/qor/actions/index/9.advanced_filter.tmpl
Normal file
41
app/views/qor/actions/index/9.advanced_filter.tmpl
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{{$filters := get_filters}}
|
||||||
|
{{if $filters}}
|
||||||
|
<div class="qor-actions qor-advanced-filter" data-toggle="qor.advancedsearch">
|
||||||
|
<button class="mdl-button mdl-button--colored qor-advanced-filter__toggle" type="button">
|
||||||
|
{{if has_filter}}
|
||||||
|
<span class="qor-notifications__unread"><i class="material-icons" style="font-size: 1.05em">edit</i></span>
|
||||||
|
{{end}}
|
||||||
|
{{t "qor_admin.filter.advanced_filter" "Advanced Filter"}}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="qor-advanced-filter__dropdown clearfix" style="display: none;" advanced-search-toggle>
|
||||||
|
<button class="mdl-button mdl-button--icon qor-advanced-filter__close">
|
||||||
|
<i class="material-icons">close</i>
|
||||||
|
</button>
|
||||||
|
<h3 class="mdl-layout-title">{{t "qor_admin.actions.advanced_filter" "Advanced Filter"}}</h3>
|
||||||
|
{{if len saved_filters}}
|
||||||
|
<div class="qor-advanced-filter__savedfilter">
|
||||||
|
<button class="mdl-button qor-advanced-filter__toggle">{{t "qor_admin.filter.saved_filter" "Saved Filter"}}</button>
|
||||||
|
<ul style="display:none;" advanced-search-toggle>
|
||||||
|
{{range $filter := saved_filters}}
|
||||||
|
<li>
|
||||||
|
<a href="{{$filter.URL}}">{{$filter.Name}}</a>
|
||||||
|
<button class="mdl-button mdl-button--icon qor-advanced-filter__delete" style="display: none;" data-filter-name="{{$filter.Name}}">
|
||||||
|
<i class="material-icons">close</i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<form method="GET">
|
||||||
|
{{range $filter := $filters}}
|
||||||
|
{{render_filter $filter}}
|
||||||
|
{{end}}
|
||||||
|
<button type="submit" class="mdl-button mdl-button--colored mdl-button--raised">{{t "qor_admin.filter.apply" "Apply"}}</button>
|
||||||
|
<button type="button" class="mdl-button mdl-button--colored qor-advanced-filter__save">{{t "qor_admin.filter.save_this_filter" "Save This Filter"}}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
BIN
app/views/qor/assets/fonts/MaterialIcons.woff
Normal file
BIN
app/views/qor/assets/fonts/MaterialIcons.woff
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-Black.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-Black.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-BlackItalic.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-BlackItalic.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-Bold.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-Bold.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-BoldItalic.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-Italic.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-Italic.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-Light.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-Light.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-LightItalic.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-LightItalic.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-Medium.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-Medium.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-MediumItalic.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-Regular.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-Regular.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-Thin.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-Thin.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/Roboto-ThinItalic.ttf
Normal file
BIN
app/views/qor/assets/fonts/Roboto-ThinItalic.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/RobotoCondensed-Bold.ttf
Normal file
BIN
app/views/qor/assets/fonts/RobotoCondensed-Bold.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/RobotoCondensed-BoldItalic.ttf
Normal file
BIN
app/views/qor/assets/fonts/RobotoCondensed-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/RobotoCondensed-Italic.ttf
Normal file
BIN
app/views/qor/assets/fonts/RobotoCondensed-Italic.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/RobotoCondensed-Light.ttf
Normal file
BIN
app/views/qor/assets/fonts/RobotoCondensed-Light.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/RobotoCondensed-LightItalic.ttf
Normal file
BIN
app/views/qor/assets/fonts/RobotoCondensed-LightItalic.ttf
Normal file
Binary file not shown.
BIN
app/views/qor/assets/fonts/RobotoCondensed-Regular.ttf
Normal file
BIN
app/views/qor/assets/fonts/RobotoCondensed-Regular.ttf
Normal file
Binary file not shown.
932
app/views/qor/assets/fonts/codepoints
Normal file
932
app/views/qor/assets/fonts/codepoints
Normal file
@@ -0,0 +1,932 @@
|
|||||||
|
3d_rotation e84d
|
||||||
|
ac_unit eb3b
|
||||||
|
access_alarm e190
|
||||||
|
access_alarms e191
|
||||||
|
access_time e192
|
||||||
|
accessibility e84e
|
||||||
|
accessible e914
|
||||||
|
account_balance e84f
|
||||||
|
account_balance_wallet e850
|
||||||
|
account_box e851
|
||||||
|
account_circle e853
|
||||||
|
adb e60e
|
||||||
|
add e145
|
||||||
|
add_a_photo e439
|
||||||
|
add_alarm e193
|
||||||
|
add_alert e003
|
||||||
|
add_box e146
|
||||||
|
add_circle e147
|
||||||
|
add_circle_outline e148
|
||||||
|
add_location e567
|
||||||
|
add_shopping_cart e854
|
||||||
|
add_to_photos e39d
|
||||||
|
add_to_queue e05c
|
||||||
|
adjust e39e
|
||||||
|
airline_seat_flat e630
|
||||||
|
airline_seat_flat_angled e631
|
||||||
|
airline_seat_individual_suite e632
|
||||||
|
airline_seat_legroom_extra e633
|
||||||
|
airline_seat_legroom_normal e634
|
||||||
|
airline_seat_legroom_reduced e635
|
||||||
|
airline_seat_recline_extra e636
|
||||||
|
airline_seat_recline_normal e637
|
||||||
|
airplanemode_active e195
|
||||||
|
airplanemode_inactive e194
|
||||||
|
airplay e055
|
||||||
|
airport_shuttle eb3c
|
||||||
|
alarm e855
|
||||||
|
alarm_add e856
|
||||||
|
alarm_off e857
|
||||||
|
alarm_on e858
|
||||||
|
album e019
|
||||||
|
all_inclusive eb3d
|
||||||
|
all_out e90b
|
||||||
|
android e859
|
||||||
|
announcement e85a
|
||||||
|
apps e5c3
|
||||||
|
archive e149
|
||||||
|
arrow_back e5c4
|
||||||
|
arrow_downward e5db
|
||||||
|
arrow_drop_down e5c5
|
||||||
|
arrow_drop_down_circle e5c6
|
||||||
|
arrow_drop_up e5c7
|
||||||
|
arrow_forward e5c8
|
||||||
|
arrow_upward e5d8
|
||||||
|
art_track e060
|
||||||
|
aspect_ratio e85b
|
||||||
|
assessment e85c
|
||||||
|
assignment e85d
|
||||||
|
assignment_ind e85e
|
||||||
|
assignment_late e85f
|
||||||
|
assignment_return e860
|
||||||
|
assignment_returned e861
|
||||||
|
assignment_turned_in e862
|
||||||
|
assistant e39f
|
||||||
|
assistant_photo e3a0
|
||||||
|
attach_file e226
|
||||||
|
attach_money e227
|
||||||
|
attachment e2bc
|
||||||
|
audiotrack e3a1
|
||||||
|
autorenew e863
|
||||||
|
av_timer e01b
|
||||||
|
backspace e14a
|
||||||
|
backup e864
|
||||||
|
battery_alert e19c
|
||||||
|
battery_charging_full e1a3
|
||||||
|
battery_full e1a4
|
||||||
|
battery_std e1a5
|
||||||
|
battery_unknown e1a6
|
||||||
|
beach_access eb3e
|
||||||
|
beenhere e52d
|
||||||
|
block e14b
|
||||||
|
bluetooth e1a7
|
||||||
|
bluetooth_audio e60f
|
||||||
|
bluetooth_connected e1a8
|
||||||
|
bluetooth_disabled e1a9
|
||||||
|
bluetooth_searching e1aa
|
||||||
|
blur_circular e3a2
|
||||||
|
blur_linear e3a3
|
||||||
|
blur_off e3a4
|
||||||
|
blur_on e3a5
|
||||||
|
book e865
|
||||||
|
bookmark e866
|
||||||
|
bookmark_border e867
|
||||||
|
border_all e228
|
||||||
|
border_bottom e229
|
||||||
|
border_clear e22a
|
||||||
|
border_color e22b
|
||||||
|
border_horizontal e22c
|
||||||
|
border_inner e22d
|
||||||
|
border_left e22e
|
||||||
|
border_outer e22f
|
||||||
|
border_right e230
|
||||||
|
border_style e231
|
||||||
|
border_top e232
|
||||||
|
border_vertical e233
|
||||||
|
branding_watermark e06b
|
||||||
|
brightness_1 e3a6
|
||||||
|
brightness_2 e3a7
|
||||||
|
brightness_3 e3a8
|
||||||
|
brightness_4 e3a9
|
||||||
|
brightness_5 e3aa
|
||||||
|
brightness_6 e3ab
|
||||||
|
brightness_7 e3ac
|
||||||
|
brightness_auto e1ab
|
||||||
|
brightness_high e1ac
|
||||||
|
brightness_low e1ad
|
||||||
|
brightness_medium e1ae
|
||||||
|
broken_image e3ad
|
||||||
|
brush e3ae
|
||||||
|
bubble_chart e6dd
|
||||||
|
bug_report e868
|
||||||
|
build e869
|
||||||
|
burst_mode e43c
|
||||||
|
business e0af
|
||||||
|
business_center eb3f
|
||||||
|
cached e86a
|
||||||
|
cake e7e9
|
||||||
|
call e0b0
|
||||||
|
call_end e0b1
|
||||||
|
call_made e0b2
|
||||||
|
call_merge e0b3
|
||||||
|
call_missed e0b4
|
||||||
|
call_missed_outgoing e0e4
|
||||||
|
call_received e0b5
|
||||||
|
call_split e0b6
|
||||||
|
call_to_action e06c
|
||||||
|
camera e3af
|
||||||
|
camera_alt e3b0
|
||||||
|
camera_enhance e8fc
|
||||||
|
camera_front e3b1
|
||||||
|
camera_rear e3b2
|
||||||
|
camera_roll e3b3
|
||||||
|
cancel e5c9
|
||||||
|
card_giftcard e8f6
|
||||||
|
card_membership e8f7
|
||||||
|
card_travel e8f8
|
||||||
|
casino eb40
|
||||||
|
cast e307
|
||||||
|
cast_connected e308
|
||||||
|
center_focus_strong e3b4
|
||||||
|
center_focus_weak e3b5
|
||||||
|
change_history e86b
|
||||||
|
chat e0b7
|
||||||
|
chat_bubble e0ca
|
||||||
|
chat_bubble_outline e0cb
|
||||||
|
check e5ca
|
||||||
|
check_box e834
|
||||||
|
check_box_outline_blank e835
|
||||||
|
check_circle e86c
|
||||||
|
chevron_left e5cb
|
||||||
|
chevron_right e5cc
|
||||||
|
child_care eb41
|
||||||
|
child_friendly eb42
|
||||||
|
chrome_reader_mode e86d
|
||||||
|
class e86e
|
||||||
|
clear e14c
|
||||||
|
clear_all e0b8
|
||||||
|
close e5cd
|
||||||
|
closed_caption e01c
|
||||||
|
cloud e2bd
|
||||||
|
cloud_circle e2be
|
||||||
|
cloud_done e2bf
|
||||||
|
cloud_download e2c0
|
||||||
|
cloud_off e2c1
|
||||||
|
cloud_queue e2c2
|
||||||
|
cloud_upload e2c3
|
||||||
|
code e86f
|
||||||
|
collections e3b6
|
||||||
|
collections_bookmark e431
|
||||||
|
color_lens e3b7
|
||||||
|
colorize e3b8
|
||||||
|
comment e0b9
|
||||||
|
compare e3b9
|
||||||
|
compare_arrows e915
|
||||||
|
computer e30a
|
||||||
|
confirmation_number e638
|
||||||
|
contact_mail e0d0
|
||||||
|
contact_phone e0cf
|
||||||
|
contacts e0ba
|
||||||
|
content_copy e14d
|
||||||
|
content_cut e14e
|
||||||
|
content_paste e14f
|
||||||
|
control_point e3ba
|
||||||
|
control_point_duplicate e3bb
|
||||||
|
copyright e90c
|
||||||
|
create e150
|
||||||
|
create_new_folder e2cc
|
||||||
|
credit_card e870
|
||||||
|
crop e3be
|
||||||
|
crop_16_9 e3bc
|
||||||
|
crop_3_2 e3bd
|
||||||
|
crop_5_4 e3bf
|
||||||
|
crop_7_5 e3c0
|
||||||
|
crop_din e3c1
|
||||||
|
crop_free e3c2
|
||||||
|
crop_landscape e3c3
|
||||||
|
crop_original e3c4
|
||||||
|
crop_portrait e3c5
|
||||||
|
crop_rotate e437
|
||||||
|
crop_square e3c6
|
||||||
|
dashboard e871
|
||||||
|
data_usage e1af
|
||||||
|
date_range e916
|
||||||
|
dehaze e3c7
|
||||||
|
delete e872
|
||||||
|
delete_forever e92b
|
||||||
|
delete_sweep e16c
|
||||||
|
description e873
|
||||||
|
desktop_mac e30b
|
||||||
|
desktop_windows e30c
|
||||||
|
details e3c8
|
||||||
|
developer_board e30d
|
||||||
|
developer_mode e1b0
|
||||||
|
device_hub e335
|
||||||
|
devices e1b1
|
||||||
|
devices_other e337
|
||||||
|
dialer_sip e0bb
|
||||||
|
dialpad e0bc
|
||||||
|
directions e52e
|
||||||
|
directions_bike e52f
|
||||||
|
directions_boat e532
|
||||||
|
directions_bus e530
|
||||||
|
directions_car e531
|
||||||
|
directions_railway e534
|
||||||
|
directions_run e566
|
||||||
|
directions_subway e533
|
||||||
|
directions_transit e535
|
||||||
|
directions_walk e536
|
||||||
|
disc_full e610
|
||||||
|
dns e875
|
||||||
|
do_not_disturb e612
|
||||||
|
do_not_disturb_alt e611
|
||||||
|
do_not_disturb_off e643
|
||||||
|
do_not_disturb_on e644
|
||||||
|
dock e30e
|
||||||
|
domain e7ee
|
||||||
|
done e876
|
||||||
|
done_all e877
|
||||||
|
donut_large e917
|
||||||
|
donut_small e918
|
||||||
|
drafts e151
|
||||||
|
drag_handle e25d
|
||||||
|
drive_eta e613
|
||||||
|
dvr e1b2
|
||||||
|
edit e3c9
|
||||||
|
edit_location e568
|
||||||
|
eject e8fb
|
||||||
|
email e0be
|
||||||
|
enhanced_encryption e63f
|
||||||
|
equalizer e01d
|
||||||
|
error e000
|
||||||
|
error_outline e001
|
||||||
|
euro_symbol e926
|
||||||
|
ev_station e56d
|
||||||
|
event e878
|
||||||
|
event_available e614
|
||||||
|
event_busy e615
|
||||||
|
event_note e616
|
||||||
|
event_seat e903
|
||||||
|
exit_to_app e879
|
||||||
|
expand_less e5ce
|
||||||
|
expand_more e5cf
|
||||||
|
explicit e01e
|
||||||
|
explore e87a
|
||||||
|
exposure e3ca
|
||||||
|
exposure_neg_1 e3cb
|
||||||
|
exposure_neg_2 e3cc
|
||||||
|
exposure_plus_1 e3cd
|
||||||
|
exposure_plus_2 e3ce
|
||||||
|
exposure_zero e3cf
|
||||||
|
extension e87b
|
||||||
|
face e87c
|
||||||
|
fast_forward e01f
|
||||||
|
fast_rewind e020
|
||||||
|
favorite e87d
|
||||||
|
favorite_border e87e
|
||||||
|
featured_play_list e06d
|
||||||
|
featured_video e06e
|
||||||
|
feedback e87f
|
||||||
|
fiber_dvr e05d
|
||||||
|
fiber_manual_record e061
|
||||||
|
fiber_new e05e
|
||||||
|
fiber_pin e06a
|
||||||
|
fiber_smart_record e062
|
||||||
|
file_download e2c4
|
||||||
|
file_upload e2c6
|
||||||
|
filter e3d3
|
||||||
|
filter_1 e3d0
|
||||||
|
filter_2 e3d1
|
||||||
|
filter_3 e3d2
|
||||||
|
filter_4 e3d4
|
||||||
|
filter_5 e3d5
|
||||||
|
filter_6 e3d6
|
||||||
|
filter_7 e3d7
|
||||||
|
filter_8 e3d8
|
||||||
|
filter_9 e3d9
|
||||||
|
filter_9_plus e3da
|
||||||
|
filter_b_and_w e3db
|
||||||
|
filter_center_focus e3dc
|
||||||
|
filter_drama e3dd
|
||||||
|
filter_frames e3de
|
||||||
|
filter_hdr e3df
|
||||||
|
filter_list e152
|
||||||
|
filter_none e3e0
|
||||||
|
filter_tilt_shift e3e2
|
||||||
|
filter_vintage e3e3
|
||||||
|
find_in_page e880
|
||||||
|
find_replace e881
|
||||||
|
fingerprint e90d
|
||||||
|
first_page e5dc
|
||||||
|
fitness_center eb43
|
||||||
|
flag e153
|
||||||
|
flare e3e4
|
||||||
|
flash_auto e3e5
|
||||||
|
flash_off e3e6
|
||||||
|
flash_on e3e7
|
||||||
|
flight e539
|
||||||
|
flight_land e904
|
||||||
|
flight_takeoff e905
|
||||||
|
flip e3e8
|
||||||
|
flip_to_back e882
|
||||||
|
flip_to_front e883
|
||||||
|
folder e2c7
|
||||||
|
folder_open e2c8
|
||||||
|
folder_shared e2c9
|
||||||
|
folder_special e617
|
||||||
|
font_download e167
|
||||||
|
format_align_center e234
|
||||||
|
format_align_justify e235
|
||||||
|
format_align_left e236
|
||||||
|
format_align_right e237
|
||||||
|
format_bold e238
|
||||||
|
format_clear e239
|
||||||
|
format_color_fill e23a
|
||||||
|
format_color_reset e23b
|
||||||
|
format_color_text e23c
|
||||||
|
format_indent_decrease e23d
|
||||||
|
format_indent_increase e23e
|
||||||
|
format_italic e23f
|
||||||
|
format_line_spacing e240
|
||||||
|
format_list_bulleted e241
|
||||||
|
format_list_numbered e242
|
||||||
|
format_paint e243
|
||||||
|
format_quote e244
|
||||||
|
format_shapes e25e
|
||||||
|
format_size e245
|
||||||
|
format_strikethrough e246
|
||||||
|
format_textdirection_l_to_r e247
|
||||||
|
format_textdirection_r_to_l e248
|
||||||
|
format_underlined e249
|
||||||
|
forum e0bf
|
||||||
|
forward e154
|
||||||
|
forward_10 e056
|
||||||
|
forward_30 e057
|
||||||
|
forward_5 e058
|
||||||
|
free_breakfast eb44
|
||||||
|
fullscreen e5d0
|
||||||
|
fullscreen_exit e5d1
|
||||||
|
functions e24a
|
||||||
|
g_translate e927
|
||||||
|
gamepad e30f
|
||||||
|
games e021
|
||||||
|
gavel e90e
|
||||||
|
gesture e155
|
||||||
|
get_app e884
|
||||||
|
gif e908
|
||||||
|
golf_course eb45
|
||||||
|
gps_fixed e1b3
|
||||||
|
gps_not_fixed e1b4
|
||||||
|
gps_off e1b5
|
||||||
|
grade e885
|
||||||
|
gradient e3e9
|
||||||
|
grain e3ea
|
||||||
|
graphic_eq e1b8
|
||||||
|
grid_off e3eb
|
||||||
|
grid_on e3ec
|
||||||
|
group e7ef
|
||||||
|
group_add e7f0
|
||||||
|
group_work e886
|
||||||
|
hd e052
|
||||||
|
hdr_off e3ed
|
||||||
|
hdr_on e3ee
|
||||||
|
hdr_strong e3f1
|
||||||
|
hdr_weak e3f2
|
||||||
|
headset e310
|
||||||
|
headset_mic e311
|
||||||
|
healing e3f3
|
||||||
|
hearing e023
|
||||||
|
help e887
|
||||||
|
help_outline e8fd
|
||||||
|
high_quality e024
|
||||||
|
highlight e25f
|
||||||
|
highlight_off e888
|
||||||
|
history e889
|
||||||
|
home e88a
|
||||||
|
hot_tub eb46
|
||||||
|
hotel e53a
|
||||||
|
hourglass_empty e88b
|
||||||
|
hourglass_full e88c
|
||||||
|
http e902
|
||||||
|
https e88d
|
||||||
|
image e3f4
|
||||||
|
image_aspect_ratio e3f5
|
||||||
|
import_contacts e0e0
|
||||||
|
import_export e0c3
|
||||||
|
important_devices e912
|
||||||
|
inbox e156
|
||||||
|
indeterminate_check_box e909
|
||||||
|
info e88e
|
||||||
|
info_outline e88f
|
||||||
|
input e890
|
||||||
|
insert_chart e24b
|
||||||
|
insert_comment e24c
|
||||||
|
insert_drive_file e24d
|
||||||
|
insert_emoticon e24e
|
||||||
|
insert_invitation e24f
|
||||||
|
insert_link e250
|
||||||
|
insert_photo e251
|
||||||
|
invert_colors e891
|
||||||
|
invert_colors_off e0c4
|
||||||
|
iso e3f6
|
||||||
|
keyboard e312
|
||||||
|
keyboard_arrow_down e313
|
||||||
|
keyboard_arrow_left e314
|
||||||
|
keyboard_arrow_right e315
|
||||||
|
keyboard_arrow_up e316
|
||||||
|
keyboard_backspace e317
|
||||||
|
keyboard_capslock e318
|
||||||
|
keyboard_hide e31a
|
||||||
|
keyboard_return e31b
|
||||||
|
keyboard_tab e31c
|
||||||
|
keyboard_voice e31d
|
||||||
|
kitchen eb47
|
||||||
|
label e892
|
||||||
|
label_outline e893
|
||||||
|
landscape e3f7
|
||||||
|
language e894
|
||||||
|
laptop e31e
|
||||||
|
laptop_chromebook e31f
|
||||||
|
laptop_mac e320
|
||||||
|
laptop_windows e321
|
||||||
|
last_page e5dd
|
||||||
|
launch e895
|
||||||
|
layers e53b
|
||||||
|
layers_clear e53c
|
||||||
|
leak_add e3f8
|
||||||
|
leak_remove e3f9
|
||||||
|
lens e3fa
|
||||||
|
library_add e02e
|
||||||
|
library_books e02f
|
||||||
|
library_music e030
|
||||||
|
lightbulb_outline e90f
|
||||||
|
line_style e919
|
||||||
|
line_weight e91a
|
||||||
|
linear_scale e260
|
||||||
|
link e157
|
||||||
|
linked_camera e438
|
||||||
|
list e896
|
||||||
|
live_help e0c6
|
||||||
|
live_tv e639
|
||||||
|
local_activity e53f
|
||||||
|
local_airport e53d
|
||||||
|
local_atm e53e
|
||||||
|
local_bar e540
|
||||||
|
local_cafe e541
|
||||||
|
local_car_wash e542
|
||||||
|
local_convenience_store e543
|
||||||
|
local_dining e556
|
||||||
|
local_drink e544
|
||||||
|
local_florist e545
|
||||||
|
local_gas_station e546
|
||||||
|
local_grocery_store e547
|
||||||
|
local_hospital e548
|
||||||
|
local_hotel e549
|
||||||
|
local_laundry_service e54a
|
||||||
|
local_library e54b
|
||||||
|
local_mall e54c
|
||||||
|
local_movies e54d
|
||||||
|
local_offer e54e
|
||||||
|
local_parking e54f
|
||||||
|
local_pharmacy e550
|
||||||
|
local_phone e551
|
||||||
|
local_pizza e552
|
||||||
|
local_play e553
|
||||||
|
local_post_office e554
|
||||||
|
local_printshop e555
|
||||||
|
local_see e557
|
||||||
|
local_shipping e558
|
||||||
|
local_taxi e559
|
||||||
|
location_city e7f1
|
||||||
|
location_disabled e1b6
|
||||||
|
location_off e0c7
|
||||||
|
location_on e0c8
|
||||||
|
location_searching e1b7
|
||||||
|
lock e897
|
||||||
|
lock_open e898
|
||||||
|
lock_outline e899
|
||||||
|
looks e3fc
|
||||||
|
looks_3 e3fb
|
||||||
|
looks_4 e3fd
|
||||||
|
looks_5 e3fe
|
||||||
|
looks_6 e3ff
|
||||||
|
looks_one e400
|
||||||
|
looks_two e401
|
||||||
|
loop e028
|
||||||
|
loupe e402
|
||||||
|
low_priority e16d
|
||||||
|
loyalty e89a
|
||||||
|
mail e158
|
||||||
|
mail_outline e0e1
|
||||||
|
map e55b
|
||||||
|
markunread e159
|
||||||
|
markunread_mailbox e89b
|
||||||
|
memory e322
|
||||||
|
menu e5d2
|
||||||
|
merge_type e252
|
||||||
|
message e0c9
|
||||||
|
mic e029
|
||||||
|
mic_none e02a
|
||||||
|
mic_off e02b
|
||||||
|
mms e618
|
||||||
|
mode_comment e253
|
||||||
|
mode_edit e254
|
||||||
|
monetization_on e263
|
||||||
|
money_off e25c
|
||||||
|
monochrome_photos e403
|
||||||
|
mood e7f2
|
||||||
|
mood_bad e7f3
|
||||||
|
more e619
|
||||||
|
more_horiz e5d3
|
||||||
|
more_vert e5d4
|
||||||
|
motorcycle e91b
|
||||||
|
mouse e323
|
||||||
|
move_to_inbox e168
|
||||||
|
movie e02c
|
||||||
|
movie_creation e404
|
||||||
|
movie_filter e43a
|
||||||
|
multiline_chart e6df
|
||||||
|
music_note e405
|
||||||
|
music_video e063
|
||||||
|
my_location e55c
|
||||||
|
nature e406
|
||||||
|
nature_people e407
|
||||||
|
navigate_before e408
|
||||||
|
navigate_next e409
|
||||||
|
navigation e55d
|
||||||
|
near_me e569
|
||||||
|
network_cell e1b9
|
||||||
|
network_check e640
|
||||||
|
network_locked e61a
|
||||||
|
network_wifi e1ba
|
||||||
|
new_releases e031
|
||||||
|
next_week e16a
|
||||||
|
nfc e1bb
|
||||||
|
no_encryption e641
|
||||||
|
no_sim e0cc
|
||||||
|
not_interested e033
|
||||||
|
note e06f
|
||||||
|
note_add e89c
|
||||||
|
notifications e7f4
|
||||||
|
notifications_active e7f7
|
||||||
|
notifications_none e7f5
|
||||||
|
notifications_off e7f6
|
||||||
|
notifications_paused e7f8
|
||||||
|
offline_pin e90a
|
||||||
|
ondemand_video e63a
|
||||||
|
opacity e91c
|
||||||
|
open_in_browser e89d
|
||||||
|
open_in_new e89e
|
||||||
|
open_with e89f
|
||||||
|
pages e7f9
|
||||||
|
pageview e8a0
|
||||||
|
palette e40a
|
||||||
|
pan_tool e925
|
||||||
|
panorama e40b
|
||||||
|
panorama_fish_eye e40c
|
||||||
|
panorama_horizontal e40d
|
||||||
|
panorama_vertical e40e
|
||||||
|
panorama_wide_angle e40f
|
||||||
|
party_mode e7fa
|
||||||
|
pause e034
|
||||||
|
pause_circle_filled e035
|
||||||
|
pause_circle_outline e036
|
||||||
|
payment e8a1
|
||||||
|
people e7fb
|
||||||
|
people_outline e7fc
|
||||||
|
perm_camera_mic e8a2
|
||||||
|
perm_contact_calendar e8a3
|
||||||
|
perm_data_setting e8a4
|
||||||
|
perm_device_information e8a5
|
||||||
|
perm_identity e8a6
|
||||||
|
perm_media e8a7
|
||||||
|
perm_phone_msg e8a8
|
||||||
|
perm_scan_wifi e8a9
|
||||||
|
person e7fd
|
||||||
|
person_add e7fe
|
||||||
|
person_outline e7ff
|
||||||
|
person_pin e55a
|
||||||
|
person_pin_circle e56a
|
||||||
|
personal_video e63b
|
||||||
|
pets e91d
|
||||||
|
phone e0cd
|
||||||
|
phone_android e324
|
||||||
|
phone_bluetooth_speaker e61b
|
||||||
|
phone_forwarded e61c
|
||||||
|
phone_in_talk e61d
|
||||||
|
phone_iphone e325
|
||||||
|
phone_locked e61e
|
||||||
|
phone_missed e61f
|
||||||
|
phone_paused e620
|
||||||
|
phonelink e326
|
||||||
|
phonelink_erase e0db
|
||||||
|
phonelink_lock e0dc
|
||||||
|
phonelink_off e327
|
||||||
|
phonelink_ring e0dd
|
||||||
|
phonelink_setup e0de
|
||||||
|
photo e410
|
||||||
|
photo_album e411
|
||||||
|
photo_camera e412
|
||||||
|
photo_filter e43b
|
||||||
|
photo_library e413
|
||||||
|
photo_size_select_actual e432
|
||||||
|
photo_size_select_large e433
|
||||||
|
photo_size_select_small e434
|
||||||
|
picture_as_pdf e415
|
||||||
|
picture_in_picture e8aa
|
||||||
|
picture_in_picture_alt e911
|
||||||
|
pie_chart e6c4
|
||||||
|
pie_chart_outlined e6c5
|
||||||
|
pin_drop e55e
|
||||||
|
place e55f
|
||||||
|
play_arrow e037
|
||||||
|
play_circle_filled e038
|
||||||
|
play_circle_outline e039
|
||||||
|
play_for_work e906
|
||||||
|
playlist_add e03b
|
||||||
|
playlist_add_check e065
|
||||||
|
playlist_play e05f
|
||||||
|
plus_one e800
|
||||||
|
poll e801
|
||||||
|
polymer e8ab
|
||||||
|
pool eb48
|
||||||
|
portable_wifi_off e0ce
|
||||||
|
portrait e416
|
||||||
|
power e63c
|
||||||
|
power_input e336
|
||||||
|
power_settings_new e8ac
|
||||||
|
pregnant_woman e91e
|
||||||
|
present_to_all e0df
|
||||||
|
print e8ad
|
||||||
|
priority_high e645
|
||||||
|
public e80b
|
||||||
|
publish e255
|
||||||
|
query_builder e8ae
|
||||||
|
question_answer e8af
|
||||||
|
queue e03c
|
||||||
|
queue_music e03d
|
||||||
|
queue_play_next e066
|
||||||
|
radio e03e
|
||||||
|
radio_button_checked e837
|
||||||
|
radio_button_unchecked e836
|
||||||
|
rate_review e560
|
||||||
|
receipt e8b0
|
||||||
|
recent_actors e03f
|
||||||
|
record_voice_over e91f
|
||||||
|
redeem e8b1
|
||||||
|
redo e15a
|
||||||
|
refresh e5d5
|
||||||
|
remove e15b
|
||||||
|
remove_circle e15c
|
||||||
|
remove_circle_outline e15d
|
||||||
|
remove_from_queue e067
|
||||||
|
remove_red_eye e417
|
||||||
|
remove_shopping_cart e928
|
||||||
|
reorder e8fe
|
||||||
|
repeat e040
|
||||||
|
repeat_one e041
|
||||||
|
replay e042
|
||||||
|
replay_10 e059
|
||||||
|
replay_30 e05a
|
||||||
|
replay_5 e05b
|
||||||
|
reply e15e
|
||||||
|
reply_all e15f
|
||||||
|
report e160
|
||||||
|
report_problem e8b2
|
||||||
|
restaurant e56c
|
||||||
|
restaurant_menu e561
|
||||||
|
restore e8b3
|
||||||
|
restore_page e929
|
||||||
|
ring_volume e0d1
|
||||||
|
room e8b4
|
||||||
|
room_service eb49
|
||||||
|
rotate_90_degrees_ccw e418
|
||||||
|
rotate_left e419
|
||||||
|
rotate_right e41a
|
||||||
|
rounded_corner e920
|
||||||
|
router e328
|
||||||
|
rowing e921
|
||||||
|
rss_feed e0e5
|
||||||
|
rv_hookup e642
|
||||||
|
satellite e562
|
||||||
|
save e161
|
||||||
|
scanner e329
|
||||||
|
schedule e8b5
|
||||||
|
school e80c
|
||||||
|
screen_lock_landscape e1be
|
||||||
|
screen_lock_portrait e1bf
|
||||||
|
screen_lock_rotation e1c0
|
||||||
|
screen_rotation e1c1
|
||||||
|
screen_share e0e2
|
||||||
|
sd_card e623
|
||||||
|
sd_storage e1c2
|
||||||
|
search e8b6
|
||||||
|
security e32a
|
||||||
|
select_all e162
|
||||||
|
send e163
|
||||||
|
sentiment_dissatisfied e811
|
||||||
|
sentiment_neutral e812
|
||||||
|
sentiment_satisfied e813
|
||||||
|
sentiment_very_dissatisfied e814
|
||||||
|
sentiment_very_satisfied e815
|
||||||
|
settings e8b8
|
||||||
|
settings_applications e8b9
|
||||||
|
settings_backup_restore e8ba
|
||||||
|
settings_bluetooth e8bb
|
||||||
|
settings_brightness e8bd
|
||||||
|
settings_cell e8bc
|
||||||
|
settings_ethernet e8be
|
||||||
|
settings_input_antenna e8bf
|
||||||
|
settings_input_component e8c0
|
||||||
|
settings_input_composite e8c1
|
||||||
|
settings_input_hdmi e8c2
|
||||||
|
settings_input_svideo e8c3
|
||||||
|
settings_overscan e8c4
|
||||||
|
settings_phone e8c5
|
||||||
|
settings_power e8c6
|
||||||
|
settings_remote e8c7
|
||||||
|
settings_system_daydream e1c3
|
||||||
|
settings_voice e8c8
|
||||||
|
share e80d
|
||||||
|
shop e8c9
|
||||||
|
shop_two e8ca
|
||||||
|
shopping_basket e8cb
|
||||||
|
shopping_cart e8cc
|
||||||
|
short_text e261
|
||||||
|
show_chart e6e1
|
||||||
|
shuffle e043
|
||||||
|
signal_cellular_4_bar e1c8
|
||||||
|
signal_cellular_connected_no_internet_4_bar e1cd
|
||||||
|
signal_cellular_no_sim e1ce
|
||||||
|
signal_cellular_null e1cf
|
||||||
|
signal_cellular_off e1d0
|
||||||
|
signal_wifi_4_bar e1d8
|
||||||
|
signal_wifi_4_bar_lock e1d9
|
||||||
|
signal_wifi_off e1da
|
||||||
|
sim_card e32b
|
||||||
|
sim_card_alert e624
|
||||||
|
skip_next e044
|
||||||
|
skip_previous e045
|
||||||
|
slideshow e41b
|
||||||
|
slow_motion_video e068
|
||||||
|
smartphone e32c
|
||||||
|
smoke_free eb4a
|
||||||
|
smoking_rooms eb4b
|
||||||
|
sms e625
|
||||||
|
sms_failed e626
|
||||||
|
snooze e046
|
||||||
|
sort e164
|
||||||
|
sort_by_alpha e053
|
||||||
|
spa eb4c
|
||||||
|
space_bar e256
|
||||||
|
speaker e32d
|
||||||
|
speaker_group e32e
|
||||||
|
speaker_notes e8cd
|
||||||
|
speaker_notes_off e92a
|
||||||
|
speaker_phone e0d2
|
||||||
|
spellcheck e8ce
|
||||||
|
star e838
|
||||||
|
star_border e83a
|
||||||
|
star_half e839
|
||||||
|
stars e8d0
|
||||||
|
stay_current_landscape e0d3
|
||||||
|
stay_current_portrait e0d4
|
||||||
|
stay_primary_landscape e0d5
|
||||||
|
stay_primary_portrait e0d6
|
||||||
|
stop e047
|
||||||
|
stop_screen_share e0e3
|
||||||
|
storage e1db
|
||||||
|
store e8d1
|
||||||
|
store_mall_directory e563
|
||||||
|
straighten e41c
|
||||||
|
streetview e56e
|
||||||
|
strikethrough_s e257
|
||||||
|
style e41d
|
||||||
|
subdirectory_arrow_left e5d9
|
||||||
|
subdirectory_arrow_right e5da
|
||||||
|
subject e8d2
|
||||||
|
subscriptions e064
|
||||||
|
subtitles e048
|
||||||
|
subway e56f
|
||||||
|
supervisor_account e8d3
|
||||||
|
surround_sound e049
|
||||||
|
swap_calls e0d7
|
||||||
|
swap_horiz e8d4
|
||||||
|
swap_vert e8d5
|
||||||
|
swap_vertical_circle e8d6
|
||||||
|
switch_camera e41e
|
||||||
|
switch_video e41f
|
||||||
|
sync e627
|
||||||
|
sync_disabled e628
|
||||||
|
sync_problem e629
|
||||||
|
system_update e62a
|
||||||
|
system_update_alt e8d7
|
||||||
|
tab e8d8
|
||||||
|
tab_unselected e8d9
|
||||||
|
tablet e32f
|
||||||
|
tablet_android e330
|
||||||
|
tablet_mac e331
|
||||||
|
tag_faces e420
|
||||||
|
tap_and_play e62b
|
||||||
|
terrain e564
|
||||||
|
text_fields e262
|
||||||
|
text_format e165
|
||||||
|
textsms e0d8
|
||||||
|
texture e421
|
||||||
|
theaters e8da
|
||||||
|
thumb_down e8db
|
||||||
|
thumb_up e8dc
|
||||||
|
thumbs_up_down e8dd
|
||||||
|
time_to_leave e62c
|
||||||
|
timelapse e422
|
||||||
|
timeline e922
|
||||||
|
timer e425
|
||||||
|
timer_10 e423
|
||||||
|
timer_3 e424
|
||||||
|
timer_off e426
|
||||||
|
title e264
|
||||||
|
toc e8de
|
||||||
|
today e8df
|
||||||
|
toll e8e0
|
||||||
|
tonality e427
|
||||||
|
touch_app e913
|
||||||
|
toys e332
|
||||||
|
track_changes e8e1
|
||||||
|
traffic e565
|
||||||
|
train e570
|
||||||
|
tram e571
|
||||||
|
transfer_within_a_station e572
|
||||||
|
transform e428
|
||||||
|
translate e8e2
|
||||||
|
trending_down e8e3
|
||||||
|
trending_flat e8e4
|
||||||
|
trending_up e8e5
|
||||||
|
tune e429
|
||||||
|
turned_in e8e6
|
||||||
|
turned_in_not e8e7
|
||||||
|
tv e333
|
||||||
|
unarchive e169
|
||||||
|
undo e166
|
||||||
|
unfold_less e5d6
|
||||||
|
unfold_more e5d7
|
||||||
|
update e923
|
||||||
|
usb e1e0
|
||||||
|
verified_user e8e8
|
||||||
|
vertical_align_bottom e258
|
||||||
|
vertical_align_center e259
|
||||||
|
vertical_align_top e25a
|
||||||
|
vibration e62d
|
||||||
|
video_call e070
|
||||||
|
video_label e071
|
||||||
|
video_library e04a
|
||||||
|
videocam e04b
|
||||||
|
videocam_off e04c
|
||||||
|
videogame_asset e338
|
||||||
|
view_agenda e8e9
|
||||||
|
view_array e8ea
|
||||||
|
view_carousel e8eb
|
||||||
|
view_column e8ec
|
||||||
|
view_comfy e42a
|
||||||
|
view_compact e42b
|
||||||
|
view_day e8ed
|
||||||
|
view_headline e8ee
|
||||||
|
view_list e8ef
|
||||||
|
view_module e8f0
|
||||||
|
view_quilt e8f1
|
||||||
|
view_stream e8f2
|
||||||
|
view_week e8f3
|
||||||
|
vignette e435
|
||||||
|
visibility e8f4
|
||||||
|
visibility_off e8f5
|
||||||
|
voice_chat e62e
|
||||||
|
voicemail e0d9
|
||||||
|
volume_down e04d
|
||||||
|
volume_mute e04e
|
||||||
|
volume_off e04f
|
||||||
|
volume_up e050
|
||||||
|
vpn_key e0da
|
||||||
|
vpn_lock e62f
|
||||||
|
wallpaper e1bc
|
||||||
|
warning e002
|
||||||
|
watch e334
|
||||||
|
watch_later e924
|
||||||
|
wb_auto e42c
|
||||||
|
wb_cloudy e42d
|
||||||
|
wb_incandescent e42e
|
||||||
|
wb_iridescent e436
|
||||||
|
wb_sunny e430
|
||||||
|
wc e63d
|
||||||
|
web e051
|
||||||
|
web_asset e069
|
||||||
|
weekend e16b
|
||||||
|
whatshot e80e
|
||||||
|
widgets e1bd
|
||||||
|
wifi e63e
|
||||||
|
wifi_lock e1e1
|
||||||
|
wifi_tethering e1e2
|
||||||
|
work e8f9
|
||||||
|
wrap_text e25b
|
||||||
|
youtube_searched_for e8fa
|
||||||
|
zoom_in e8ff
|
||||||
|
zoom_out e900
|
||||||
|
zoom_out_map e56b
|
||||||
BIN
app/views/qor/assets/images/bg-transparents.png
Normal file
BIN
app/views/qor/assets/images/bg-transparents.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 970 B |
10
app/views/qor/assets/images/icon_trangle.svg
Normal file
10
app/views/qor/assets/images/icon_trangle.svg
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="12px" height="6px" viewBox="0 0 12 6" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch Beta 40 (33747) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>Shape</title>
|
||||||
|
<desc>Created with Sketch Beta.</desc>
|
||||||
|
<defs></defs>
|
||||||
|
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<polygon id="Shape" fill="#010101" transform="translate(6.000000, 3.000000) scale(1, -1) translate(-6.000000, -3.000000) " points="0 6 6 0 12 6"></polygon>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 632 B |
BIN
app/views/qor/assets/images/logo.png
Normal file
BIN
app/views/qor/assets/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 327 B |
1
app/views/qor/assets/javascripts/app.js
Normal file
1
app/views/qor/assets/javascripts/app.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"use strict";$(function(){$(document).on("click.qor.alert",'[data-dismiss="alert"]',function(){$(this).closest(".qor-alert").removeClass("qor-alert__active")}),setTimeout(function(){$('.qor-alert[data-dismissible="true"]').removeClass("qor-alert__active")},5e3)}),$(function(){$(document).on("click",".qor-dialog--global-search",function(e){e.stopPropagation(),$(e.target).parents(".qor-dialog-content").length||$(e.target).is(".qor-dialog-content")||$(".qor-dialog--global-search").remove()}),$(document).on("click",".qor-global-search--show",function(e){e.preventDefault();var a=$(this).data(),o=window.Mustache.render('<div class="qor-dialog qor-dialog--global-search" tabindex="-1" role="dialog" aria-hidden="true"><div class="qor-dialog-content"><form action=[[actionUrl]]><div class="mdl-textfield mdl-js-textfield" id="global-search-textfield"><input class="mdl-textfield__input ignore-dirtyform" name="keyword" id="globalSearch" value="" type="text" placeholder="" /><label class="mdl-textfield__label" for="globalSearch">[[placeholder]]</label></div></form></div></div>',a);$("body").append(o),window.componentHandler.upgradeElement(document.getElementById("global-search-textfield")),$("#globalSearch").focus()})}),$(function(){var l=[],s="qoradmin_menu_status",e=localStorage.getItem(s);e&&e.length&&(l=e.split(",")),$(".qor-menu-container").on("click","> ul > li > a",function(){var e=$(this),a=e.parent(),o=e.next("ul"),t=a.attr("qor-icon-name");o.length&&(o.hasClass("in")?(l.push(t),a.removeClass("is-expanded"),o.one("transitionend",function(){o.removeClass("collapsing in")}).addClass("collapsing").height(0)):(l=_.without(l,t),a.addClass("is-expanded"),o.one("transitionend",function(){o.removeClass("collapsing")}).addClass("collapsing in").height(o.prop("scrollHeight"))),localStorage.setItem(s,l))}).find("> ul > li > a").each(function(){var e=$(this),a=e.parent(),o=e.next("ul"),t=a.attr("qor-icon-name");o.length&&(o.addClass("collapse"),a.addClass("has-menu"),-1!=l.indexOf(t)?o.height(0):(a.addClass("is-expanded"),o.addClass("in").height(o.prop("scrollHeight"))))});var a=$(".qor-page > .qor-page__header"),o=$(".qor-page > .qor-page__body"),t=a.find(".qor-page-subnav__header").length?96:48;a.length&&(a.height()>t&&o.css("padding-top",a.height()),$(".qor-page").addClass("has-header"),$("header.mdl-layout__header").addClass("has-action"))}),$(function(){$(".qor-mobile--show-actions").on("click",function(){$(".qor-page__header").toggleClass("actions-show")})}),$(function(){var p,m,q=$("body"),f="is-selected",b=function(){return q.hasClass("qor-bottomsheets-open")};function _(e){$("[data-url]").removeClass(f),e&&e.length&&e.addClass(f)}q.qorBottomSheets(),q.qorSlideout(),p=q.data("qor.slideout"),m=q.data("qor.bottomsheets"),$(document).on("click.qor.openUrl","[data-url]",function(e){var a,o=$(this),t=$(e.target),l=o.hasClass("qor-button--new"),s=o.hasClass("qor-button--edit"),n=(o.is(".qor-table tr[data-url]")||o.closest(".qor-js-table").length)&&!o.closest(".qor-slideout").length,r=o.data(),i=r.openType,d=o.parents(".qor-theme-slideout").length,c=o.closest(".qor-slideout").length,h=o.hasClass("qor-action-button")||o.hasClass("qor-action--button");if(e.stopPropagation(),!(o.data("ajax-form")||t.closest(".qor-table--bulking").length||t.closest(".qor-button--actions").length||!t.data("url")&&t.is("a")||n&&b()))if("window"!=i){var u,g;if("new_window"!=i)return h&&(u=$(".qor-js-table tbody").find(".mdl-checkbox__input:checked"),g=[],(a=!!u.length&&(u.each(function(){g.push($(this).closest("tr").data("primary-key"))}),g))&&(r=$.extend({},r,{actionData:a}))),r.$target=t,r.method&&"GET"!=r.method.toUpperCase()?void 0:("bottomsheet"!=i&&!h||"slideout"==i?"slideout"==i||n||l&&!b()||s?"slideout"==i||d?o.hasClass(f)?(p.hide(),_()):(p.open(r),_(o)):window.location.href=r.url:q.hasClass("qor-slideout-open")||l&&b()?m.open(r):d?p.open(r):m.open(r):h&&!a&&o.closest('[data-toggle="qor.action.bulk"]').length&&!c?window.QOR.qorConfirm(r.errorNoItem):m.open(r),!1);window.open(r.url,"_blank")}else window.location.href=r.url})}),$(function(){var l=window.location;$(".qor-search").each(function(){var e=$(this),a=e.find(".qor-search__input"),o=e.find(".qor-search__clear"),t=!!a.val();e.closest(".qor-page__header").addClass("has-search"),$("header.mdl-layout__header").addClass("has-search"),o.on("click",function(){a.val()||t?"?"==l.search.replace(new RegExp(a.attr("name")+"\\=?\\w*"),"")?l.href=l.href.split("?")[0]:l.search=l.search.replace(new RegExp(a.attr("name")+"\\=?\\w*"),""):e.removeClass("is-dirty")})})});
|
||||||
13
app/views/qor/assets/javascripts/app/alert.js
Normal file
13
app/views/qor/assets/javascripts/app/alert.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
$(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
$(document).on('click.qor.alert', '[data-dismiss="alert"]', function() {
|
||||||
|
$(this)
|
||||||
|
.closest('.qor-alert')
|
||||||
|
.removeClass('qor-alert__active');
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
$('.qor-alert[data-dismissible="true"]').removeClass('qor-alert__active');
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
36
app/views/qor/assets/javascripts/app/global-search.js
Normal file
36
app/views/qor/assets/javascripts/app/global-search.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
$(function () {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var modal = (
|
||||||
|
'<div class="qor-dialog qor-dialog--global-search" tabindex="-1" role="dialog" aria-hidden="true">' +
|
||||||
|
'<div class="qor-dialog-content">' +
|
||||||
|
'<form action=[[actionUrl]]>' +
|
||||||
|
'<div class="mdl-textfield mdl-js-textfield" id="global-search-textfield">' +
|
||||||
|
'<input class="mdl-textfield__input ignore-dirtyform" name="keyword" id="globalSearch" value="" type="text" placeholder="" />' +
|
||||||
|
'<label class="mdl-textfield__label" for="globalSearch">[[placeholder]]</label>' +
|
||||||
|
'</div>' +
|
||||||
|
'</form>' +
|
||||||
|
'</div>' +
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
|
||||||
|
$(document).on('click', '.qor-dialog--global-search', function(e){
|
||||||
|
e.stopPropagation();
|
||||||
|
if (!$(e.target).parents('.qor-dialog-content').length && !$(e.target).is('.qor-dialog-content')){
|
||||||
|
$('.qor-dialog--global-search').remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('click', '.qor-global-search--show', function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var data = $(this).data();
|
||||||
|
var modalHTML = window.Mustache.render(modal, data);
|
||||||
|
|
||||||
|
$('body').append(modalHTML);
|
||||||
|
window.componentHandler.upgradeElement(document.getElementById('global-search-textfield'));
|
||||||
|
$('#globalSearch').focus();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
80
app/views/qor/assets/javascripts/app/menu.js
Normal file
80
app/views/qor/assets/javascripts/app/menu.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
$(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let menuDatas = [],
|
||||||
|
storageName = 'qoradmin_menu_status',
|
||||||
|
lastMenuStatus = localStorage.getItem(storageName);
|
||||||
|
|
||||||
|
if (lastMenuStatus && lastMenuStatus.length) {
|
||||||
|
menuDatas = lastMenuStatus.split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
$('.qor-menu-container')
|
||||||
|
.on('click', '> ul > li > a', function() {
|
||||||
|
let $this = $(this),
|
||||||
|
$li = $this.parent(),
|
||||||
|
$ul = $this.next('ul'),
|
||||||
|
menuName = $li.attr('qor-icon-name');
|
||||||
|
|
||||||
|
if (!$ul.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ul.hasClass('in')) {
|
||||||
|
menuDatas.push(menuName);
|
||||||
|
|
||||||
|
$li.removeClass('is-expanded');
|
||||||
|
$ul
|
||||||
|
.one('transitionend', function() {
|
||||||
|
$ul.removeClass('collapsing in');
|
||||||
|
})
|
||||||
|
.addClass('collapsing')
|
||||||
|
.height(0);
|
||||||
|
} else {
|
||||||
|
menuDatas = _.without(menuDatas, menuName);
|
||||||
|
|
||||||
|
$li.addClass('is-expanded');
|
||||||
|
$ul
|
||||||
|
.one('transitionend', function() {
|
||||||
|
$ul.removeClass('collapsing');
|
||||||
|
})
|
||||||
|
.addClass('collapsing in')
|
||||||
|
.height($ul.prop('scrollHeight'));
|
||||||
|
}
|
||||||
|
localStorage.setItem(storageName, menuDatas);
|
||||||
|
})
|
||||||
|
.find('> ul > li > a')
|
||||||
|
.each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
$li = $this.parent(),
|
||||||
|
$ul = $this.next('ul'),
|
||||||
|
menuName = $li.attr('qor-icon-name');
|
||||||
|
|
||||||
|
if (!$ul.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ul.addClass('collapse');
|
||||||
|
$li.addClass('has-menu');
|
||||||
|
|
||||||
|
if (menuDatas.indexOf(menuName) != -1) {
|
||||||
|
$ul.height(0);
|
||||||
|
} else {
|
||||||
|
$li.addClass('is-expanded');
|
||||||
|
$ul.addClass('in').height($ul.prop('scrollHeight'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let $pageHeader = $('.qor-page > .qor-page__header'),
|
||||||
|
$pageBody = $('.qor-page > .qor-page__body'),
|
||||||
|
triggerHeight = $pageHeader.find('.qor-page-subnav__header').length ? 96 : 48;
|
||||||
|
|
||||||
|
if ($pageHeader.length) {
|
||||||
|
if ($pageHeader.height() > triggerHeight) {
|
||||||
|
$pageBody.css('padding-top', $pageHeader.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
$('.qor-page').addClass('has-header');
|
||||||
|
$('header.mdl-layout__header').addClass('has-action');
|
||||||
|
}
|
||||||
|
});
|
||||||
5
app/views/qor/assets/javascripts/app/mobile.js
Normal file
5
app/views/qor/assets/javascripts/app/mobile.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
$(function () {
|
||||||
|
$('.qor-mobile--show-actions').on('click', function () {
|
||||||
|
$('.qor-page__header').toggleClass('actions-show');
|
||||||
|
});
|
||||||
|
});
|
||||||
162
app/views/qor/assets/javascripts/app/open-url.js
Normal file
162
app/views/qor/assets/javascripts/app/open-url.js
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
$(function() {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let $body = $("body"),
|
||||||
|
Slideout,
|
||||||
|
BottomSheets,
|
||||||
|
CLASS_IS_SELECTED = "is-selected",
|
||||||
|
isSlideoutOpened = function() {
|
||||||
|
return $body.hasClass("qor-slideout-open");
|
||||||
|
},
|
||||||
|
isBottomsheetsOpened = function() {
|
||||||
|
return $body.hasClass("qor-bottomsheets-open");
|
||||||
|
};
|
||||||
|
|
||||||
|
$body.qorBottomSheets();
|
||||||
|
$body.qorSlideout();
|
||||||
|
|
||||||
|
Slideout = $body.data("qor.slideout");
|
||||||
|
BottomSheets = $body.data("qor.bottomsheets");
|
||||||
|
|
||||||
|
function toggleSelectedCss(ele) {
|
||||||
|
$("[data-url]").removeClass(CLASS_IS_SELECTED);
|
||||||
|
ele && ele.length && ele.addClass(CLASS_IS_SELECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectSelectID() {
|
||||||
|
let $checked = $(".qor-js-table tbody").find(
|
||||||
|
".mdl-checkbox__input:checked"
|
||||||
|
),
|
||||||
|
IDs = [];
|
||||||
|
|
||||||
|
if (!$checked.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$checked.each(function() {
|
||||||
|
IDs.push(
|
||||||
|
$(this)
|
||||||
|
.closest("tr")
|
||||||
|
.data("primary-key")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return IDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on("click.qor.openUrl", "[data-url]", function(e) {
|
||||||
|
let $this = $(this),
|
||||||
|
$target = $(e.target),
|
||||||
|
isNewButton = $this.hasClass("qor-button--new"),
|
||||||
|
isEditButton = $this.hasClass("qor-button--edit"),
|
||||||
|
isInTable =
|
||||||
|
($this.is(".qor-table tr[data-url]") ||
|
||||||
|
$this.closest(".qor-js-table").length) &&
|
||||||
|
!$this.closest(".qor-slideout").length, // if table is in slideout, will open bottom sheet
|
||||||
|
openData = $this.data(),
|
||||||
|
actionData,
|
||||||
|
openType = openData.openType,
|
||||||
|
hasSlideoutTheme = $this.parents(".qor-theme-slideout").length,
|
||||||
|
isInSlideout = $this.closest(".qor-slideout").length,
|
||||||
|
isActionButton =
|
||||||
|
$this.hasClass("qor-action-button") ||
|
||||||
|
$this.hasClass("qor-action--button");
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
// if clicking item's menu actions
|
||||||
|
if (
|
||||||
|
$this.data("ajax-form") ||
|
||||||
|
$target.closest(".qor-table--bulking").length ||
|
||||||
|
$target.closest(".qor-button--actions").length ||
|
||||||
|
(!$target.data("url") && $target.is("a")) ||
|
||||||
|
(isInTable && isBottomsheetsOpened())
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openType == "window") {
|
||||||
|
window.location.href = openData.url;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openType == "new_window") {
|
||||||
|
window.open(openData.url, "_blank");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isActionButton) {
|
||||||
|
actionData = collectSelectID();
|
||||||
|
if (actionData) {
|
||||||
|
openData = $.extend({}, openData, {
|
||||||
|
actionData: actionData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openData.$target = $target;
|
||||||
|
|
||||||
|
if (!openData.method || openData.method.toUpperCase() == "GET") {
|
||||||
|
// Open in BottmSheet: is action button, open type is bottom-sheet
|
||||||
|
// is action button but opentype == slideout, should open in slideout\
|
||||||
|
// open type is No.1 priority
|
||||||
|
|
||||||
|
if (
|
||||||
|
(openType == "bottomsheet" || isActionButton) &&
|
||||||
|
openType != "slideout"
|
||||||
|
) {
|
||||||
|
// if is bulk action and no item selected
|
||||||
|
if (
|
||||||
|
isActionButton &&
|
||||||
|
!actionData &&
|
||||||
|
$this.closest('[data-toggle="qor.action.bulk"]').length &&
|
||||||
|
!isInSlideout
|
||||||
|
) {
|
||||||
|
window.QOR.qorConfirm(openData.errorNoItem);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BottomSheets.open(openData);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slideout or New Page: table items, new button, edit button
|
||||||
|
if (
|
||||||
|
openType == "slideout" ||
|
||||||
|
isInTable ||
|
||||||
|
(isNewButton && !isBottomsheetsOpened()) ||
|
||||||
|
isEditButton
|
||||||
|
) {
|
||||||
|
if (openType == "slideout" || hasSlideoutTheme) {
|
||||||
|
if ($this.hasClass(CLASS_IS_SELECTED)) {
|
||||||
|
Slideout.hide();
|
||||||
|
toggleSelectedCss();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
Slideout.open(openData);
|
||||||
|
toggleSelectedCss($this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.location.href = openData.url;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open in BottmSheet: slideout is opened or openType is Bottom Sheet
|
||||||
|
if (isSlideoutOpened() || (isNewButton && isBottomsheetsOpened())) {
|
||||||
|
BottomSheets.open(openData);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other clicks
|
||||||
|
if (hasSlideoutTheme) {
|
||||||
|
Slideout.open(openData);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
BottomSheets.open(openData);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
33
app/views/qor/assets/javascripts/app/search.js
Normal file
33
app/views/qor/assets/javascripts/app/search.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
$(function () {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var location = window.location;
|
||||||
|
|
||||||
|
$('.qor-search').each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var $input = $this.find('.qor-search__input');
|
||||||
|
var $clear = $this.find('.qor-search__clear');
|
||||||
|
var isSearched = !!$input.val();
|
||||||
|
|
||||||
|
var emptySearch = function () {
|
||||||
|
var search = location.search.replace(new RegExp($input.attr('name') + '\\=?\\w*'), '');
|
||||||
|
if (search == '?'){
|
||||||
|
location.href = location.href.split('?')[0];
|
||||||
|
} else {
|
||||||
|
location.search = location.search.replace(new RegExp($input.attr('name') + '\\=?\\w*'), '');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$this.closest('.qor-page__header').addClass('has-search');
|
||||||
|
$('header.mdl-layout__header').addClass('has-search');
|
||||||
|
|
||||||
|
$clear.on('click', function () {
|
||||||
|
if ($input.val() || isSearched) {
|
||||||
|
emptySearch();
|
||||||
|
} else {
|
||||||
|
$this.removeClass('is-dirty');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
5
app/views/qor/assets/javascripts/datetimepicker.js
Normal file
5
app/views/qor/assets/javascripts/datetimepicker.js
Normal file
File diff suppressed because one or more lines are too long
1
app/views/qor/assets/javascripts/qor.js
Normal file
1
app/views/qor/assets/javascripts/qor.js
Normal file
File diff suppressed because one or more lines are too long
1458
app/views/qor/assets/javascripts/qor/datepicker.js
Normal file
1458
app/views/qor/assets/javascripts/qor/datepicker.js
Normal file
File diff suppressed because it is too large
Load Diff
408
app/views/qor/assets/javascripts/qor/qor-action.js
Normal file
408
app/views/qor/assets/javascripts/qor/qor-action.js
Normal file
@@ -0,0 +1,408 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
let Mustache = window.Mustache,
|
||||||
|
QOR = window.QOR,
|
||||||
|
NAMESPACE = 'qor.action',
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
EVENT_UNDO = 'undo.' + NAMESPACE,
|
||||||
|
CLASS_ACTION_FORMS = '.qor-action-forms',
|
||||||
|
CLASS_MENU_ACTIONS = '[data-ajax-form="true"][data-method]',
|
||||||
|
CLASS_BUTTON_BULKS = '.qor-action-bulk-buttons',
|
||||||
|
CLASS_TABLE = '.qor-page .qor-table-container',
|
||||||
|
CLASS_TABLE_BULK = '.qor-table--bulking',
|
||||||
|
CLASS_TABLE_BULK_TR = '.qor-table--bulking tbody tr',
|
||||||
|
CLASS_IS_UNDO = 'is_undo',
|
||||||
|
CLASS_TABLE_MDL = 'mdl-data-table--selectable',
|
||||||
|
CLASS_SLIDEOUT = '.qor-slideout',
|
||||||
|
ACTION_FORM_DATA = 'primary_values[]',
|
||||||
|
CLASS_HEADER_TOGGLE = '.qor-page__header .qor-actions, .qor-page__header .qor-search-container',
|
||||||
|
CLASS_BODY_LOADING = ".qor-body__loading";
|
||||||
|
|
||||||
|
function QorAction(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorAction.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.ajaxForm = {};
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorAction.prototype = {
|
||||||
|
constructor: QorAction,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.bind();
|
||||||
|
this.initActions();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$element.on(EVENT_CLICK, '.qor-action--bulk', this.renderBulkTable.bind(this)).on(EVENT_CLICK, '.qor-action--exit-bulk', this.removeBulkTable.bind(this));
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_CLICK, CLASS_TABLE_BULK_TR, this.handleBulkTableClick.bind(this))
|
||||||
|
.on(EVENT_CLICK, CLASS_MENU_ACTIONS, this.clickAjaxButton.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element.off(EVENT_CLICK);
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.off(EVENT_CLICK, CLASS_TABLE_BULK_TR, this.handleBulkTableClick)
|
||||||
|
.off(EVENT_CLICK, CLASS_MENU_ACTIONS, this.clickAjaxButton);
|
||||||
|
},
|
||||||
|
|
||||||
|
initActions: function() {
|
||||||
|
if (!$(CLASS_TABLE).find('table').length) {
|
||||||
|
$(CLASS_BUTTON_BULKS).hide();
|
||||||
|
$('.qor-page__header a.qor-action--button').hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
collectFormData: function() {
|
||||||
|
let checkedInputs = $(CLASS_TABLE_BULK).find('.mdl-checkbox__input:checked'),
|
||||||
|
formData = [],
|
||||||
|
normalFormData = [],
|
||||||
|
tempObj;
|
||||||
|
|
||||||
|
if (checkedInputs.length) {
|
||||||
|
checkedInputs.each(function() {
|
||||||
|
let id = $(this)
|
||||||
|
.closest('tr')
|
||||||
|
.data('primary-key');
|
||||||
|
|
||||||
|
tempObj = {};
|
||||||
|
if (id) {
|
||||||
|
formData.push({
|
||||||
|
name: ACTION_FORM_DATA,
|
||||||
|
value: id.toString()
|
||||||
|
});
|
||||||
|
|
||||||
|
tempObj[ACTION_FORM_DATA] = id.toString();
|
||||||
|
normalFormData.push(tempObj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.ajaxForm.formData = formData;
|
||||||
|
this.ajaxForm.normalFormData = normalFormData;
|
||||||
|
return this.ajaxForm;
|
||||||
|
},
|
||||||
|
|
||||||
|
actionSubmit: function($action) {
|
||||||
|
this.submit($action);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleBulkTableClick: function(e) {
|
||||||
|
let $target = $(e.target).closest('tr'),
|
||||||
|
$firstTd = $target.find('td').first(),
|
||||||
|
$checkbox = $firstTd.find('.mdl-js-checkbox');
|
||||||
|
|
||||||
|
$checkbox.toggleClass('is-checked');
|
||||||
|
$target.toggleClass('is-selected');
|
||||||
|
$firstTd.find('input').prop('checked', $checkbox.hasClass('is-checked'));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
adjustPageBodyStyle: function(isRender) {
|
||||||
|
let $pageHeader = $('.qor-page > .qor-page__header'),
|
||||||
|
$pageBody = $('.qor-page > .qor-page__body'),
|
||||||
|
triggerHeight = $pageHeader.find('.qor-page-subnav__header').length ? 96 : 48;
|
||||||
|
|
||||||
|
if (isRender) {
|
||||||
|
if ($pageHeader.height() > triggerHeight) {
|
||||||
|
$pageBody.css('padding-top', $pageHeader.height());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (parseInt($pageBody.css('padding-top')) > triggerHeight) {
|
||||||
|
$pageBody.css('padding-top', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
renderBulkTable: function() {
|
||||||
|
let $body = $('body');
|
||||||
|
|
||||||
|
if ($body.hasClass('qor-slideout-open')) {
|
||||||
|
$body.data('qor.slideout').hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
$('.qor-table__inner-list').remove();
|
||||||
|
this.toggleBulkButtons();
|
||||||
|
this.enableTableMDL();
|
||||||
|
this.adjustPageBodyStyle(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeBulkTable: function() {
|
||||||
|
this.toggleBulkButtons();
|
||||||
|
this.disableTableMDL();
|
||||||
|
this.adjustPageBodyStyle();
|
||||||
|
},
|
||||||
|
|
||||||
|
enableTableMDL: function() {
|
||||||
|
$(CLASS_TABLE)
|
||||||
|
.find('table')
|
||||||
|
.removeAttr('data-upgraded')
|
||||||
|
.addClass(CLASS_TABLE_MDL)
|
||||||
|
.trigger('enable');
|
||||||
|
},
|
||||||
|
|
||||||
|
disableTableMDL: function() {
|
||||||
|
$(CLASS_TABLE)
|
||||||
|
.find('table')
|
||||||
|
.removeClass(CLASS_TABLE_MDL)
|
||||||
|
.find('tr')
|
||||||
|
.removeClass('is-selected')
|
||||||
|
.find('td:first,th:first')
|
||||||
|
.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleBulkButtons: function() {
|
||||||
|
this.$element.find(CLASS_ACTION_FORMS).toggle();
|
||||||
|
$(CLASS_BUTTON_BULKS)
|
||||||
|
.find('button')
|
||||||
|
.toggleClass('hidden');
|
||||||
|
|
||||||
|
$(CLASS_TABLE)
|
||||||
|
.toggleClass('qor-table--bulking')
|
||||||
|
.find('.qor-table__actions')
|
||||||
|
.toggle();
|
||||||
|
|
||||||
|
$(CLASS_HEADER_TOGGLE).toggle();
|
||||||
|
},
|
||||||
|
|
||||||
|
clickAjaxButton: function(e) {
|
||||||
|
let $target = $(e.target);
|
||||||
|
|
||||||
|
this.collectFormData();
|
||||||
|
this.ajaxForm.properties = $target.data();
|
||||||
|
this.submit($target);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
renderFlashMessage: function(data) {
|
||||||
|
let flashMessageTmpl = QorAction.FLASHMESSAGETMPL;
|
||||||
|
Mustache.parse(flashMessageTmpl);
|
||||||
|
return Mustache.render(flashMessageTmpl, data);
|
||||||
|
},
|
||||||
|
|
||||||
|
addLoading: function() {
|
||||||
|
$(CLASS_BODY_LOADING).remove();
|
||||||
|
var $loading = $(QorAction.TEMPLATE_LOADING);
|
||||||
|
$loading.appendTo($("body")).trigger("enable.qor.material");
|
||||||
|
},
|
||||||
|
|
||||||
|
submit: function($actionButton) {
|
||||||
|
let _this = this,
|
||||||
|
ajaxForm = this.ajaxForm || {},
|
||||||
|
properties = ajaxForm.properties || $actionButton.data();
|
||||||
|
|
||||||
|
|
||||||
|
if($actionButton.hasClass("qor-action-disabled")){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.fromIndex && (!ajaxForm.formData || !ajaxForm.formData.length)) {
|
||||||
|
QOR.qorConfirm(ajaxForm.properties.errorNoItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.confirm) {
|
||||||
|
QOR.qorConfirm(properties, function(confirm) {
|
||||||
|
if (confirm) {
|
||||||
|
_this.handleAjaxSubmit(ajaxForm, $actionButton);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.handleAjaxSubmit(ajaxForm, $actionButton);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleAjaxSubmit: function(ajaxForm, $actionButton) {
|
||||||
|
let _this = this,
|
||||||
|
$element = this.$element,
|
||||||
|
$parent = $actionButton.closest(".qor-action-forms"),
|
||||||
|
properties = ajaxForm.properties || $actionButton.data(),
|
||||||
|
url = properties.url,
|
||||||
|
undoUrl = properties.undoUrl,
|
||||||
|
isUndo = $actionButton.hasClass(CLASS_IS_UNDO),
|
||||||
|
isInSlideout = $actionButton.closest(CLASS_SLIDEOUT).length,
|
||||||
|
needDisableButtons = $element.length && !isInSlideout;
|
||||||
|
|
||||||
|
if (isUndo) {
|
||||||
|
url = undoUrl; // notification has undo url
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addLoading();
|
||||||
|
if($parent.length){
|
||||||
|
$parent.find('[data-ajax-form="true"][data-method]').addClass("qor-action-disabled");
|
||||||
|
} else {
|
||||||
|
$actionButton.addClass("qor-action-disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$.ajax(url, {
|
||||||
|
method: properties.method,
|
||||||
|
data: ajaxForm.formData,
|
||||||
|
dataType: properties.datatype || 'json',
|
||||||
|
beforeSend: function() {
|
||||||
|
if (undoUrl) {
|
||||||
|
$actionButton.prop('disabled', true);
|
||||||
|
} else if (needDisableButtons) {
|
||||||
|
_this.switchButtons($element, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
// has undo action
|
||||||
|
if (undoUrl) {
|
||||||
|
$element.trigger(EVENT_UNDO, [$actionButton, isUndo, data]);
|
||||||
|
isUndo ? $actionButton.removeClass(CLASS_IS_UNDO) : $actionButton.addClass(CLASS_IS_UNDO);
|
||||||
|
$actionButton.prop('disabled', false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
error: function(err) {
|
||||||
|
if (err.status == 200) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (undoUrl) {
|
||||||
|
$actionButton.prop('disabled', false);
|
||||||
|
} else if (needDisableButtons) {
|
||||||
|
_this.switchButtons($element);
|
||||||
|
}
|
||||||
|
|
||||||
|
QOR.handleAjaxError(err);
|
||||||
|
},
|
||||||
|
complete: function(response) {
|
||||||
|
let contentType = response.getResponseHeader('content-type'),
|
||||||
|
disposition = response.getResponseHeader('Content-Disposition');
|
||||||
|
|
||||||
|
$(CLASS_BODY_LOADING).remove();
|
||||||
|
$actionButton.prop('disabled', false);
|
||||||
|
if($parent.length){
|
||||||
|
$parent.find('[data-ajax-form="true"][data-method]').removeClass("qor-action-disabled");
|
||||||
|
} else {
|
||||||
|
$actionButton.removeClass("qor-action-disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle file download from form submit
|
||||||
|
if (disposition && disposition.indexOf('attachment') !== -1) {
|
||||||
|
var fileNameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/,
|
||||||
|
matches = fileNameRegex.exec(disposition),
|
||||||
|
fileData = {},
|
||||||
|
fileName = '';
|
||||||
|
|
||||||
|
if (matches != null && matches[1]) {
|
||||||
|
fileName = matches[1].replace(/['"]/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.method) {
|
||||||
|
fileData = $.extend({}, ajaxForm.normalFormData, {
|
||||||
|
_method: properties.method
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
QOR.qorAjaxHandleFile(url, contentType, fileName, fileData);
|
||||||
|
|
||||||
|
if (undoUrl) {
|
||||||
|
$actionButton.prop('disabled', false);
|
||||||
|
} else {
|
||||||
|
_this.switchButtons($element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
switchButtons: function($element, disbale) {
|
||||||
|
let needDisbale = disbale ? true : false;
|
||||||
|
$element.find('.qor-action-button').prop('disabled', needDisbale);
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorAction.DEFAULTS = {};
|
||||||
|
|
||||||
|
QorAction.TEMPLATE_LOADING = `<div class="qor-body__loading">
|
||||||
|
<div class="mdl-dialog-bg"></div>
|
||||||
|
<div><div class="mdl-spinner mdl-js-spinner is-active qor-layout__bottomsheet-spinner"></div></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
$.fn.qorSliderAfterShow.qorInsertActionData = function(url, html) {
|
||||||
|
let $action = $(html).find('[data-toggle="qor-action-slideout"]'),
|
||||||
|
$actionForm = $action.find('form'),
|
||||||
|
$checkedItem = $(CLASS_TABLE_BULK).find('.mdl-checkbox__input:checked');
|
||||||
|
|
||||||
|
if ($action.length && $checkedItem.length) {
|
||||||
|
// insert checked value into sliderout form
|
||||||
|
$checkedItem.each(function() {
|
||||||
|
let id = $(this)
|
||||||
|
.closest('tr')
|
||||||
|
.data('primary-key');
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
$actionForm.prepend('<input class="js-primary-value" type="hidden" name="primary_values[]" value="' + id + '" />');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorAction.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
data = $this.data(NAMESPACE),
|
||||||
|
fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
$this.data(NAMESPACE, (data = new QorAction(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.call(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
let options = {},
|
||||||
|
selector = '[data-toggle="qor.action.bulk"]';
|
||||||
|
|
||||||
|
if (!$(selector).length) {
|
||||||
|
$(document).on(EVENT_CLICK, CLASS_MENU_ACTIONS, function(e) {
|
||||||
|
new QorAction().actionSubmit($(e.target));
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorAction.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorAction.plugin.call($(selector, e.target), options);
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorAction;
|
||||||
|
});
|
||||||
272
app/views/qor/assets/javascripts/qor/qor-advanced-search.js
Normal file
272
app/views/qor/assets/javascripts/qor/qor-advanced-search.js
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === "function" && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(["jquery"], factory);
|
||||||
|
} else if (typeof exports === "object") {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require("jquery"));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let location = window.location,
|
||||||
|
QOR = window.QOR,
|
||||||
|
NAMESPACE = "qor.advancedsearch",
|
||||||
|
EVENT_ENABLE = "enable." + NAMESPACE,
|
||||||
|
EVENT_DISABLE = "disable." + NAMESPACE,
|
||||||
|
EVENT_CLICK = "click." + NAMESPACE,
|
||||||
|
EVENT_SHOWN = "shown.qor.modal",
|
||||||
|
EVENT_SUBMIT = "submit." + NAMESPACE;
|
||||||
|
|
||||||
|
function getExtraPairs(names) {
|
||||||
|
let pairs = decodeURIComponent(location.search.substr(1)).split("&"),
|
||||||
|
pairsObj = {},
|
||||||
|
pair,
|
||||||
|
i;
|
||||||
|
|
||||||
|
if (pairs.length == 1 && pairs[0] == "") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in pairs) {
|
||||||
|
if (pairs[i] === "") continue;
|
||||||
|
|
||||||
|
pair = pairs[i].split("=");
|
||||||
|
pairsObj[pair[0]] = pair[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
names.forEach(function(item) {
|
||||||
|
delete pairsObj[item];
|
||||||
|
});
|
||||||
|
|
||||||
|
return pairsObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function QorAdvancedSearch(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend(
|
||||||
|
{},
|
||||||
|
QorAdvancedSearch.DEFAULTS,
|
||||||
|
$.isPlainObject(options) && options
|
||||||
|
);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorAdvancedSearch.prototype = {
|
||||||
|
constructor: QorAdvancedSearch,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.$form = this.$element.find("form");
|
||||||
|
this.$modal = $(QorAdvancedSearch.MODAL).appendTo("body");
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$element
|
||||||
|
.on(EVENT_SUBMIT, "form", this.submit.bind(this))
|
||||||
|
.on(
|
||||||
|
EVENT_CLICK,
|
||||||
|
".qor-advanced-filter__save",
|
||||||
|
this.showSaveFilter.bind(this)
|
||||||
|
)
|
||||||
|
.on(
|
||||||
|
EVENT_CLICK,
|
||||||
|
".qor-advanced-filter__toggle",
|
||||||
|
this.toggleFilterContent
|
||||||
|
)
|
||||||
|
.on(EVENT_CLICK, ".qor-advanced-filter__close", this.closeFilter)
|
||||||
|
.on(
|
||||||
|
EVENT_CLICK,
|
||||||
|
".qor-advanced-filter__delete",
|
||||||
|
this.deleteSavedFilter
|
||||||
|
);
|
||||||
|
|
||||||
|
this.$modal.on(EVENT_SHOWN, this.start.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
closeFilter: function() {
|
||||||
|
$(".qor-advanced-filter__dropdown").hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleFilterContent: function(e) {
|
||||||
|
$(e.target)
|
||||||
|
.closest(".qor-advanced-filter__toggle")
|
||||||
|
.parent()
|
||||||
|
.find(">[advanced-search-toggle]")
|
||||||
|
.toggle();
|
||||||
|
},
|
||||||
|
|
||||||
|
showSaveFilter: function() {
|
||||||
|
this.$modal.qorModal("show");
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteSavedFilter: function(e) {
|
||||||
|
let $target = $(e.target).closest(".qor-advanced-filter__delete"),
|
||||||
|
$savedFilter = $target.closest(".qor-advanced-filter__savedfilter"),
|
||||||
|
name = $target.data("filter-name"),
|
||||||
|
url = location.pathname,
|
||||||
|
message = {
|
||||||
|
confirm: "Are you sure you want to delete this saved filter?"
|
||||||
|
};
|
||||||
|
|
||||||
|
QOR.qorConfirm(message, function(confirm) {
|
||||||
|
if (confirm) {
|
||||||
|
$.get(url, $.param({ delete_saved_filter: name }))
|
||||||
|
.done(function() {
|
||||||
|
$target.closest("li").remove();
|
||||||
|
if ($savedFilter.find("li").length === 0) {
|
||||||
|
$savedFilter.remove();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fail(function() {
|
||||||
|
QOR.qorConfirm("Server error, please try again!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
start: function() {
|
||||||
|
this.$modal
|
||||||
|
.trigger("enable.qor.material")
|
||||||
|
.on(
|
||||||
|
EVENT_CLICK,
|
||||||
|
".qor-advanced-filter__savefilter",
|
||||||
|
this.saveFilter.bind(this)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
saveFilter: function() {
|
||||||
|
let name = this.$modal.find("#qor-advanced-filter__savename").val();
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$form
|
||||||
|
.prepend(
|
||||||
|
`<input type="hidden" name="filter_saving_name" value="${name}" />`
|
||||||
|
)
|
||||||
|
.submit();
|
||||||
|
},
|
||||||
|
|
||||||
|
submit: function() {
|
||||||
|
let $form = this.$form,
|
||||||
|
formArr = $form.find("input[name],select[name]"),
|
||||||
|
names = [],
|
||||||
|
extraPairs,
|
||||||
|
$bottomsheet = $form.closest(".qor-bottomsheets"),
|
||||||
|
params = $form.serialize();
|
||||||
|
|
||||||
|
formArr.each(function() {
|
||||||
|
names.push($(this).attr("name"));
|
||||||
|
});
|
||||||
|
|
||||||
|
extraPairs = getExtraPairs(names);
|
||||||
|
|
||||||
|
if (!$.isEmptyObject(extraPairs)) {
|
||||||
|
for (let key in extraPairs) {
|
||||||
|
if (extraPairs.hasOwnProperty(key)) {
|
||||||
|
$form.prepend(
|
||||||
|
`<input type="hidden" name=${key} value=${extraPairs[key]} />`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$element.find(".qor-advanced-filter__dropdown").hide();
|
||||||
|
|
||||||
|
this.removeEmptyPairs($form);
|
||||||
|
|
||||||
|
if ($bottomsheet.length) {
|
||||||
|
if ($bottomsheet.data().url) {
|
||||||
|
let reloadUrl = `${$bottomsheet.data().url}?${params}`;
|
||||||
|
$bottomsheet.trigger("reloadFromUrl.qor.bottomsheets", [reloadUrl]);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
console.log("dont have base URL! advancedsearch reload failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
removeEmptyPairs: function($form) {
|
||||||
|
$form.find("advanced-filter-group").each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
$input = $this.find("[filter-required]");
|
||||||
|
if ($input.val() == "") {
|
||||||
|
$this.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorAdvancedSearch.DEFAULTS = {};
|
||||||
|
|
||||||
|
QorAdvancedSearch.MODAL = `<div class="qor-modal fade" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div class="mdl-card mdl-shadow--2dp" role="document">
|
||||||
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">Save advanced filter</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting-text">
|
||||||
|
|
||||||
|
<div class="mdl-textfield mdl-textfield--full-width mdl-js-textfield">
|
||||||
|
<input class="mdl-textfield__input" type="text" id="qor-advanced-filter__savename">
|
||||||
|
<label class="mdl-textfield__label" for="qor-advanced-filter__savename">Please enter name for this filter</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__actions">
|
||||||
|
<a class="mdl-button mdl-button--colored mdl-button--raised qor-advanced-filter__savefilter">Save This Filter</a>
|
||||||
|
<a class="mdl-button mdl-button--colored" data-dismiss="modal">Cancel</a>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__menu">
|
||||||
|
<button class="mdl-button mdl-button--icon" data-dismiss="modal" aria-label="close">
|
||||||
|
<i class="material-icons">close</i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorAdvancedSearch.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
data = $this.data(NAMESPACE),
|
||||||
|
fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorAdvancedSearch(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === "string" && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
let selector = '[data-toggle="qor.advancedsearch"]',
|
||||||
|
options;
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorAdvancedSearch.plugin.call($(selector, e.target), "destroy");
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorAdvancedSearch.plugin.call($(selector, e.target), options);
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorAdvancedSearch;
|
||||||
|
});
|
||||||
101
app/views/qor/assets/javascripts/qor/qor-autoheight.js
Normal file
101
app/views/qor/assets/javascripts/qor/qor-autoheight.js
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
(function (factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function ($) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var NAMESPACE = 'qor.autoheight';
|
||||||
|
var EVENT_ENABLE = 'enable.' + NAMESPACE;
|
||||||
|
var EVENT_DISABLE = 'disable.' + NAMESPACE;
|
||||||
|
var EVENT_INPUT = 'input';
|
||||||
|
|
||||||
|
function QorAutoheight(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorAutoheight.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorAutoheight.prototype = {
|
||||||
|
constructor: QorAutoheight,
|
||||||
|
|
||||||
|
init: function () {
|
||||||
|
var $this = this.$element;
|
||||||
|
|
||||||
|
this.paddingTop = parseInt($this.css('padding-top'), 10);
|
||||||
|
this.paddingBottom = parseInt($this.css('padding-bottom'), 10);
|
||||||
|
this.resize();
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function () {
|
||||||
|
this.$element.on(EVENT_INPUT, $.proxy(this.resize, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function () {
|
||||||
|
this.$element.off(EVENT_INPUT, this.resize);
|
||||||
|
},
|
||||||
|
|
||||||
|
resize: function () {
|
||||||
|
var $this = this.$element;
|
||||||
|
var scrollHeight = $this.prop('scrollHeight');
|
||||||
|
|
||||||
|
if(scrollHeight){
|
||||||
|
$this.height('auto').height(scrollHeight - this.paddingTop - this.paddingBottom);
|
||||||
|
} else {
|
||||||
|
$this.height('40px');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorAutoheight.DEFAULTS = {};
|
||||||
|
|
||||||
|
QorAutoheight.plugin = function (options) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorAutoheight(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction(fn = data[options])) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
var selector = 'textarea.qor-js-autoheight';
|
||||||
|
|
||||||
|
$(document).
|
||||||
|
on(EVENT_DISABLE, function (e) {
|
||||||
|
QorAutoheight.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
}).
|
||||||
|
on(EVENT_ENABLE, function (e) {
|
||||||
|
QorAutoheight.plugin.call($(selector, e.target));
|
||||||
|
}).
|
||||||
|
triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorAutoheight;
|
||||||
|
|
||||||
|
});
|
||||||
754
app/views/qor/assets/javascripts/qor/qor-bottomsheets.js
Normal file
754
app/views/qor/assets/javascripts/qor/qor-bottomsheets.js
Normal file
@@ -0,0 +1,754 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === "function" && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(["jquery"], factory);
|
||||||
|
} else if (typeof exports === "object") {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require("jquery"));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let _ = window._,
|
||||||
|
FormData = window.FormData,
|
||||||
|
QOR_Translations = window.QOR_Translations,
|
||||||
|
NAMESPACE = "qor.bottomsheets",
|
||||||
|
EVENT_CLICK = "click." + NAMESPACE,
|
||||||
|
EVENT_SUBMIT = "submit." + NAMESPACE,
|
||||||
|
EVENT_SUBMITED = "ajaxSuccessed." + NAMESPACE,
|
||||||
|
EVENT_RELOAD = "reload." + NAMESPACE,
|
||||||
|
EVENT_RELOADFROMURL = "reloadFromUrl." + NAMESPACE,
|
||||||
|
EVENT_BOTTOMSHEET_BEFORESEND = "bottomsheetBeforeSend." + NAMESPACE,
|
||||||
|
EVENT_BOTTOMSHEET_LOADED = "bottomsheetLoaded." + NAMESPACE,
|
||||||
|
EVENT_BOTTOMSHEET_CLOSED = "bottomsheetClosed." + NAMESPACE,
|
||||||
|
EVENT_BOTTOMSHEET_SUBMIT = "bottomsheetSubmitComplete." + NAMESPACE,
|
||||||
|
EVENT_HIDDEN = "hidden." + NAMESPACE,
|
||||||
|
EVENT_KEYUP = "keyup." + NAMESPACE,
|
||||||
|
CLASS_OPEN = "qor-bottomsheets-open",
|
||||||
|
CLASS_IS_SHOWN = "is-shown",
|
||||||
|
CLASS_IS_SLIDED = "is-slided",
|
||||||
|
CLASS_MAIN_CONTENT = ".mdl-layout__content.qor-page",
|
||||||
|
CLASS_BODY_CONTENT = ".qor-page__body",
|
||||||
|
CLASS_BODY_HEAD = ".qor-page__header",
|
||||||
|
CLASS_BOTTOMSHEETS_FILTER = ".qor-bottomsheet__filter",
|
||||||
|
CLASS_BOTTOMSHEETS_BUTTON = ".qor-bottomsheets__search-button",
|
||||||
|
CLASS_BOTTOMSHEETS_INPUT = ".qor-bottomsheets__search-input",
|
||||||
|
URL_GETQOR = "http://www.getqor.com/";
|
||||||
|
|
||||||
|
function getUrlParameter(name, search) {
|
||||||
|
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
||||||
|
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
|
||||||
|
var results = regex.exec(decodeURIComponent(search));
|
||||||
|
return results === null
|
||||||
|
? ""
|
||||||
|
: results[1].replace(/\+/g, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateQueryStringParameter(key, value, uri) {
|
||||||
|
var escapedkey = String(key).replace(/[\\^$*+?.()|[\]{}]/g, "\\$&"),
|
||||||
|
re = new RegExp("([?&])" + escapedkey + "=.*?(&|$)", "i"),
|
||||||
|
separator = uri.indexOf("?") !== -1 ? "&" : "?";
|
||||||
|
|
||||||
|
if (uri.match(re)) {
|
||||||
|
if (value) {
|
||||||
|
return uri.replace(re, "$1" + key + "=" + value + "$2");
|
||||||
|
} else {
|
||||||
|
if (RegExp.$1 === "?" || RegExp.$1 === RegExp.$2) {
|
||||||
|
return uri.replace(re, "$1");
|
||||||
|
} else {
|
||||||
|
return uri.replace(re, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (value) {
|
||||||
|
return uri + separator + key + "=" + value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushArrary($ele, isScript) {
|
||||||
|
let array = [],
|
||||||
|
prop = "href";
|
||||||
|
|
||||||
|
isScript && (prop = "src");
|
||||||
|
$ele.each(function() {
|
||||||
|
array.push($(this).attr(prop));
|
||||||
|
});
|
||||||
|
return _.uniq(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
function execSlideoutEvents(url, response) {
|
||||||
|
// exec qorSliderAfterShow after script loaded
|
||||||
|
var qorSliderAfterShow = $.fn.qorSliderAfterShow;
|
||||||
|
for (var name in qorSliderAfterShow) {
|
||||||
|
if (
|
||||||
|
qorSliderAfterShow.hasOwnProperty(name) &&
|
||||||
|
!qorSliderAfterShow[name]["isLoadedInBottomSheet"] &&
|
||||||
|
name != "initPublishForm" &&
|
||||||
|
name != "qorActivityinit"
|
||||||
|
) {
|
||||||
|
qorSliderAfterShow[name]["isLoadedInBottomSheet"] = true;
|
||||||
|
qorSliderAfterShow[name].call(this, url, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadScripts(srcs, data, callback) {
|
||||||
|
let scriptsLoaded = 0;
|
||||||
|
|
||||||
|
for (let i = 0, len = srcs.length; i < len; i++) {
|
||||||
|
let script = document.createElement("script");
|
||||||
|
|
||||||
|
script.onload = function() {
|
||||||
|
scriptsLoaded++;
|
||||||
|
|
||||||
|
if (scriptsLoaded === srcs.length) {
|
||||||
|
if ($.isFunction(callback)) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data && data.url && data.response) {
|
||||||
|
execSlideoutEvents(data.url, data.response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
script.src = srcs[i];
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadStyles(srcs) {
|
||||||
|
let ss = document.createElement("link"),
|
||||||
|
src = srcs.shift();
|
||||||
|
|
||||||
|
ss.type = "text/css";
|
||||||
|
ss.rel = "stylesheet";
|
||||||
|
ss.onload = function() {
|
||||||
|
if (srcs.length) {
|
||||||
|
loadStyles(srcs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ss.href = src;
|
||||||
|
document.getElementsByTagName("head")[0].appendChild(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareScripts($scripts) {
|
||||||
|
let $currentPageScripts = $("script"),
|
||||||
|
slideoutScripts = pushArrary($scripts, true),
|
||||||
|
currentPageScripts = pushArrary($currentPageScripts, true),
|
||||||
|
scriptDiff = _.difference(slideoutScripts, currentPageScripts);
|
||||||
|
return scriptDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareLinks($links) {
|
||||||
|
let $currentStyles = $("link"),
|
||||||
|
slideoutStyles = pushArrary($links),
|
||||||
|
currentStyles = pushArrary($currentStyles),
|
||||||
|
styleDiff = _.difference(slideoutStyles, currentStyles);
|
||||||
|
|
||||||
|
return styleDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function QorBottomSheets(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend(
|
||||||
|
{},
|
||||||
|
QorBottomSheets.DEFAULTS,
|
||||||
|
$.isPlainObject(options) && options
|
||||||
|
);
|
||||||
|
this.resourseData = {};
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorBottomSheets.prototype = {
|
||||||
|
constructor: QorBottomSheets,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.build();
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
build: function() {
|
||||||
|
let $bottomsheets;
|
||||||
|
|
||||||
|
this.$bottomsheets = $bottomsheets = $(QorBottomSheets.TEMPLATE).appendTo(
|
||||||
|
"body"
|
||||||
|
);
|
||||||
|
this.$body = $bottomsheets.find(".qor-bottomsheets__body");
|
||||||
|
this.$title = $bottomsheets.find(".qor-bottomsheets__title");
|
||||||
|
this.$header = $bottomsheets.find(".qor-bottomsheets__header");
|
||||||
|
this.$bodyClass = $("body").prop("class");
|
||||||
|
this.filterURL = "";
|
||||||
|
this.searchParams = "";
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$bottomsheets
|
||||||
|
.on(EVENT_SUBMIT, "form", this.submit.bind(this))
|
||||||
|
.on(EVENT_CLICK, '[data-dismiss="bottomsheets"]', this.hide.bind(this))
|
||||||
|
.on(EVENT_CLICK, ".qor-pagination-container a", this.pagination.bind(this))
|
||||||
|
.on(EVENT_CLICK, CLASS_BOTTOMSHEETS_BUTTON, this.search.bind(this))
|
||||||
|
.on(EVENT_KEYUP, this.keyup.bind(this))
|
||||||
|
.on("selectorChanged.qor.selector", this.selectorChanged.bind(this))
|
||||||
|
.on("filterChanged.qor.filter", this.filterChanged.bind(this))
|
||||||
|
.on(EVENT_RELOADFROMURL, this.reloadFromUrl.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$bottomsheets
|
||||||
|
.off(EVENT_SUBMIT, "form")
|
||||||
|
.off(EVENT_CLICK)
|
||||||
|
.off("selectorChanged.qor.selector")
|
||||||
|
.off("filterChanged.qor.filter");
|
||||||
|
},
|
||||||
|
|
||||||
|
bindActionData: function(actiondData) {
|
||||||
|
var $form = this.$body
|
||||||
|
.find('[data-toggle="qor-action-slideout"]')
|
||||||
|
.find("form");
|
||||||
|
for (var i = actiondData.length - 1; i >= 0; i--) {
|
||||||
|
$form.prepend(
|
||||||
|
'<input type="hidden" name="primary_values[]" value="' +
|
||||||
|
actiondData[i] +
|
||||||
|
'" />'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
filterChanged: function(e, search, key) {
|
||||||
|
// if this event triggered:
|
||||||
|
// search: ?locale_mode=locale, ?filters[Color].Value=2
|
||||||
|
// key: search param name: locale_mode
|
||||||
|
|
||||||
|
var loadUrl;
|
||||||
|
|
||||||
|
loadUrl = this.constructloadURL(search, key);
|
||||||
|
loadUrl && this.reload(loadUrl);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
selectorChanged: function(e, url, key) {
|
||||||
|
// if this event triggered:
|
||||||
|
// url: /admin/!remote_data_searcher/products/Collections?locale=en-US
|
||||||
|
// key: search param key: locale
|
||||||
|
|
||||||
|
var loadUrl;
|
||||||
|
|
||||||
|
loadUrl = this.constructloadURL(url, key);
|
||||||
|
loadUrl && this.reload(loadUrl);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
keyup: function(e) {
|
||||||
|
var searchInput = this.$bottomsheets.find(CLASS_BOTTOMSHEETS_INPUT);
|
||||||
|
|
||||||
|
if (e.which === 13 && searchInput.length && searchInput.is(":focus")) {
|
||||||
|
this.search();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
search: function() {
|
||||||
|
var $bottomsheets = this.$bottomsheets,
|
||||||
|
param = "?keyword=",
|
||||||
|
baseUrl = $bottomsheets.data().url,
|
||||||
|
searchValue = $.trim(
|
||||||
|
$bottomsheets.find(CLASS_BOTTOMSHEETS_INPUT).val()
|
||||||
|
),
|
||||||
|
url = baseUrl + param + searchValue;
|
||||||
|
|
||||||
|
if(/\?/g.test(baseUrl)){
|
||||||
|
url = baseUrl + "&keyword=" + searchValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reload(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
pagination: function(e) {
|
||||||
|
var $ele = $(e.target).closest("a"),
|
||||||
|
url = $ele.prop("href");
|
||||||
|
if (url) {
|
||||||
|
this.reload(url);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
reload: function(url) {
|
||||||
|
var $content = this.$bottomsheets.find(CLASS_BODY_CONTENT);
|
||||||
|
|
||||||
|
this.addLoading($content);
|
||||||
|
this.fetchPage(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
reloadFromUrl: function(e, url) {
|
||||||
|
this.reload(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchPage: function(url) {
|
||||||
|
var $bottomsheets = this.$bottomsheets,
|
||||||
|
_this = this;
|
||||||
|
|
||||||
|
$.get(url, function(response) {
|
||||||
|
var $response = $(response).find(CLASS_MAIN_CONTENT),
|
||||||
|
$responseHeader = $response.find(CLASS_BODY_HEAD),
|
||||||
|
$responseBody = $response.find(CLASS_BODY_CONTENT);
|
||||||
|
|
||||||
|
if ($responseBody.length) {
|
||||||
|
$bottomsheets.find(CLASS_BODY_CONTENT).html($responseBody.html());
|
||||||
|
|
||||||
|
if ($responseHeader.length) {
|
||||||
|
_this.$body
|
||||||
|
.find(CLASS_BODY_HEAD)
|
||||||
|
.html($responseHeader.html())
|
||||||
|
.trigger("enable");
|
||||||
|
_this.addHeaderClass();
|
||||||
|
}
|
||||||
|
// will trigger this event(relaod.qor.bottomsheets) when bottomsheets reload complete: like pagination, filter, action etc.
|
||||||
|
$bottomsheets.trigger(EVENT_RELOAD);
|
||||||
|
} else {
|
||||||
|
_this.reload(url);
|
||||||
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
window.alert("server error, please try again later!");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
constructloadURL: function(url, key) {
|
||||||
|
var fakeURL,
|
||||||
|
value,
|
||||||
|
filterURL = this.filterURL,
|
||||||
|
bindUrl = this.$bottomsheets.data().url;
|
||||||
|
|
||||||
|
if (!filterURL) {
|
||||||
|
if (bindUrl) {
|
||||||
|
filterURL = bindUrl;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeURL = new URL(URL_GETQOR + url);
|
||||||
|
value = getUrlParameter(key, fakeURL.search);
|
||||||
|
filterURL = this.filterURL = updateQueryStringParameter(
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
filterURL
|
||||||
|
);
|
||||||
|
|
||||||
|
return filterURL;
|
||||||
|
},
|
||||||
|
|
||||||
|
addHeaderClass: function() {
|
||||||
|
this.$body.find(CLASS_BODY_HEAD).hide();
|
||||||
|
if (
|
||||||
|
this.$bottomsheets
|
||||||
|
.find(CLASS_BODY_HEAD)
|
||||||
|
.children(CLASS_BOTTOMSHEETS_FILTER).length
|
||||||
|
) {
|
||||||
|
this.$body
|
||||||
|
.addClass("has-header")
|
||||||
|
.find(CLASS_BODY_HEAD)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addLoading: function($element) {
|
||||||
|
$element.html("");
|
||||||
|
$(QorBottomSheets.TEMPLATE_LOADING)
|
||||||
|
.appendTo($element)
|
||||||
|
.trigger("enable.qor.material");
|
||||||
|
},
|
||||||
|
|
||||||
|
loadExtraResource: function(data) {
|
||||||
|
let styleDiff = compareLinks(data.$links),
|
||||||
|
scriptDiff = compareScripts(data.$scripts);
|
||||||
|
|
||||||
|
styleDiff.length && loadStyles(styleDiff);
|
||||||
|
scriptDiff.length && loadScripts(scriptDiff, data);
|
||||||
|
},
|
||||||
|
|
||||||
|
loadMedialibraryJS: function($response) {
|
||||||
|
var $script = $response.filter("script"),
|
||||||
|
theme = /theme=media_library/g,
|
||||||
|
src,
|
||||||
|
_this = this;
|
||||||
|
|
||||||
|
$script.each(function() {
|
||||||
|
src = $(this).prop("src");
|
||||||
|
if (theme.test(src)) {
|
||||||
|
var script = document.createElement("script");
|
||||||
|
script.src = src;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
_this.mediaScriptAdded = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
submit: function(e) {
|
||||||
|
let form = e.target,
|
||||||
|
$form = $(form),
|
||||||
|
_this = this,
|
||||||
|
url = $form.prop("action"),
|
||||||
|
formData,
|
||||||
|
$bottomsheets = $form.closest(".qor-bottomsheets"),
|
||||||
|
resourseData = $bottomsheets.data(),
|
||||||
|
ajaxType = resourseData.ajaxType,
|
||||||
|
$submit = $form.find(":submit");
|
||||||
|
|
||||||
|
// will ingore submit event if need handle with other submit event: like select one, many...
|
||||||
|
if (resourseData.ingoreSubmit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// will submit form as normal,
|
||||||
|
// if you need download file after submit form or other things, please add
|
||||||
|
// data-use-normal-submit="true" to form tag
|
||||||
|
// <form action="/admin/products/!action/localize" method="POST" enctype="multipart/form-data" data-normal-submit="true"></form>
|
||||||
|
var normalSubmit = $form.data().normalSubmit;
|
||||||
|
|
||||||
|
if (normalSubmit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).trigger(EVENT_BOTTOMSHEET_BEFORESEND);
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
formData = new FormData(form);
|
||||||
|
|
||||||
|
$.ajax(url, {
|
||||||
|
method: $form.prop("method"),
|
||||||
|
data: formData,
|
||||||
|
dataType: ajaxType ? ajaxType : "html",
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
beforeSend: function() {
|
||||||
|
$submit.prop("disabled", true);
|
||||||
|
},
|
||||||
|
success: function(data, textStatus, jqXHR) {
|
||||||
|
if (resourseData.ajaxMute) {
|
||||||
|
$bottomsheets.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourseData.ajaxTakeover) {
|
||||||
|
resourseData.$target
|
||||||
|
.parent()
|
||||||
|
.trigger(EVENT_SUBMITED, [data, $bottomsheets]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle file download from form submit
|
||||||
|
var disposition = jqXHR.getResponseHeader("Content-Disposition");
|
||||||
|
if (disposition && disposition.indexOf("attachment") !== -1) {
|
||||||
|
var fileNameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/,
|
||||||
|
matches = fileNameRegex.exec(disposition),
|
||||||
|
contentType = jqXHR.getResponseHeader("Content-Type"),
|
||||||
|
fileName = "";
|
||||||
|
|
||||||
|
if (matches != null && matches[1]) {
|
||||||
|
fileName = matches[1].replace(/['"]/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
window.QOR.qorAjaxHandleFile(url, contentType, fileName, formData);
|
||||||
|
$submit.prop("disabled", false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(".qor-error").remove();
|
||||||
|
|
||||||
|
var returnUrl = $form.data("returnUrl");
|
||||||
|
var refreshUrl = $form.data("refreshUrl");
|
||||||
|
|
||||||
|
if (refreshUrl) {
|
||||||
|
window.location.href = refreshUrl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnUrl == "refresh") {
|
||||||
|
_this.refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnUrl && returnUrl != "refresh") {
|
||||||
|
_this.load(returnUrl);
|
||||||
|
} else {
|
||||||
|
_this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).trigger(EVENT_BOTTOMSHEET_SUBMIT);
|
||||||
|
},
|
||||||
|
error: function(err) {
|
||||||
|
window.QOR.handleAjaxError(err);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
$submit.prop("disabled", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
load: function(url, data, callback) {
|
||||||
|
var options = this.options,
|
||||||
|
method,
|
||||||
|
dataType,
|
||||||
|
load,
|
||||||
|
actionData = data.actionData,
|
||||||
|
resourseData = this.resourseData,
|
||||||
|
selectModal = resourseData.selectModal,
|
||||||
|
ingoreSubmit = resourseData.ingoreSubmit,
|
||||||
|
$bottomsheets = this.$bottomsheets,
|
||||||
|
$header = this.$header,
|
||||||
|
$body = this.$body;
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.show();
|
||||||
|
this.addLoading($body);
|
||||||
|
|
||||||
|
this.filterURL = url;
|
||||||
|
$body.removeClass("has-header has-hint");
|
||||||
|
|
||||||
|
data = $.isPlainObject(data) ? data : {};
|
||||||
|
|
||||||
|
method = data.method ? data.method : "GET";
|
||||||
|
dataType = data.datatype ? data.datatype : "html";
|
||||||
|
|
||||||
|
load = $.proxy(function() {
|
||||||
|
$.ajax(url, {
|
||||||
|
method: method,
|
||||||
|
dataType: dataType,
|
||||||
|
success: $.proxy(function(response) {
|
||||||
|
if (method === "GET") {
|
||||||
|
let $response = $(response),
|
||||||
|
$content,
|
||||||
|
bodyClass,
|
||||||
|
loadExtraResourceData = {
|
||||||
|
$scripts: $response.filter("script"),
|
||||||
|
$links: $response.filter("link"),
|
||||||
|
url: url,
|
||||||
|
response: response
|
||||||
|
},
|
||||||
|
hasSearch =
|
||||||
|
selectModal && $response.find(".qor-search-container").length,
|
||||||
|
bodyHtml = response.match(/<\s*body.*>[\s\S]*<\s*\/body\s*>/gi);
|
||||||
|
|
||||||
|
$content = $response.find(CLASS_MAIN_CONTENT);
|
||||||
|
|
||||||
|
if (bodyHtml) {
|
||||||
|
bodyHtml = bodyHtml
|
||||||
|
.join("")
|
||||||
|
.replace(/<\s*body/gi, "<div")
|
||||||
|
.replace(/<\s*\/body/gi, "</div");
|
||||||
|
bodyClass = $(bodyHtml).prop("class");
|
||||||
|
$("body").addClass(bodyClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$content.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadExtraResource(loadExtraResourceData);
|
||||||
|
|
||||||
|
if (ingoreSubmit) {
|
||||||
|
$content.find(CLASS_BODY_HEAD).remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
$content
|
||||||
|
.find(".qor-button--cancel")
|
||||||
|
.attr("data-dismiss", "bottomsheets");
|
||||||
|
|
||||||
|
$body.html($content.html());
|
||||||
|
this.$title.html($response.find(options.title).html());
|
||||||
|
|
||||||
|
if (data.selectDefaultCreating) {
|
||||||
|
this.$title.append(
|
||||||
|
`<button class="mdl-button mdl-button--primary" type="button" data-load-inline="true" data-select-nohint="${
|
||||||
|
data.selectNohint
|
||||||
|
}" data-select-modal="${
|
||||||
|
data.selectModal
|
||||||
|
}" data-select-listing-url="${data.selectListingUrl}">${
|
||||||
|
data.selectBacktolistTitle
|
||||||
|
}</button>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectModal) {
|
||||||
|
$body
|
||||||
|
.find(".qor-button--new")
|
||||||
|
.data("ingoreSubmit", true)
|
||||||
|
.data("selectId", resourseData.selectId)
|
||||||
|
.data("loadInline", true);
|
||||||
|
if (
|
||||||
|
selectModal != "one" &&
|
||||||
|
!data.selectNohint &&
|
||||||
|
(typeof resourseData.maxItem === "undefined" ||
|
||||||
|
resourseData.maxItem != "1")
|
||||||
|
) {
|
||||||
|
$body.addClass("has-hint");
|
||||||
|
}
|
||||||
|
if (selectModal == "mediabox" && !this.mediaScriptAdded) {
|
||||||
|
this.loadMedialibraryJS($response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$header.find(".qor-button--new").remove();
|
||||||
|
this.$title.after($body.find(".qor-button--new"));
|
||||||
|
|
||||||
|
if (hasSearch) {
|
||||||
|
$bottomsheets.addClass("has-search");
|
||||||
|
$header.find(".qor-bottomsheets__search").remove();
|
||||||
|
$header.prepend(QorBottomSheets.TEMPLATE_SEARCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionData && actionData.length) {
|
||||||
|
this.bindActionData(actionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourseData.bottomsheetClassname) {
|
||||||
|
$bottomsheets.addClass(resourseData.bottomsheetClassname);
|
||||||
|
}
|
||||||
|
|
||||||
|
$bottomsheets.trigger("enable");
|
||||||
|
|
||||||
|
$bottomsheets.one(EVENT_HIDDEN, function() {
|
||||||
|
$(this).trigger("disable");
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addHeaderClass();
|
||||||
|
$bottomsheets.data(data);
|
||||||
|
|
||||||
|
// handle after opened callback
|
||||||
|
if (callback && $.isFunction(callback)) {
|
||||||
|
callback(this.$bottomsheets);
|
||||||
|
}
|
||||||
|
|
||||||
|
// callback for after bottomSheets loaded HTML
|
||||||
|
$bottomsheets.trigger(EVENT_BOTTOMSHEET_LOADED, [url, response]);
|
||||||
|
} else {
|
||||||
|
if (data.returnUrl) {
|
||||||
|
this.load(data.returnUrl);
|
||||||
|
} else {
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this),
|
||||||
|
|
||||||
|
error: $.proxy(function() {
|
||||||
|
this.$bottomsheets.remove();
|
||||||
|
if (!$(".qor-bottomsheets").is(":visible")) {
|
||||||
|
$("body").removeClass(CLASS_OPEN);
|
||||||
|
}
|
||||||
|
var errors;
|
||||||
|
if ($(".qor-error span").length > 0) {
|
||||||
|
errors = $(".qor-error span")
|
||||||
|
.map(function() {
|
||||||
|
return $(this).text();
|
||||||
|
})
|
||||||
|
.get()
|
||||||
|
.join(", ");
|
||||||
|
} else {
|
||||||
|
errors = QOR_Translations.serverError;
|
||||||
|
}
|
||||||
|
window.alert(errors);
|
||||||
|
}, this)
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
load();
|
||||||
|
},
|
||||||
|
|
||||||
|
open: function(options, callback) {
|
||||||
|
if (!options.loadInline) {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
this.resourseData = options;
|
||||||
|
this.load(options.url, options, callback);
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function() {
|
||||||
|
this.$bottomsheets.addClass(CLASS_IS_SHOWN).get(0).offsetHeight;
|
||||||
|
this.$bottomsheets.addClass(CLASS_IS_SLIDED);
|
||||||
|
$("body").addClass(CLASS_OPEN);
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function(e) {
|
||||||
|
let $bottomsheets = $(e.target).closest(".qor-bottomsheets"),
|
||||||
|
$datePicker = $(".qor-datepicker").not(".hidden");
|
||||||
|
|
||||||
|
if ($datePicker.length) {
|
||||||
|
$datePicker.addClass("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
$bottomsheets.qorSelectCore("destroy");
|
||||||
|
|
||||||
|
$bottomsheets.trigger(EVENT_BOTTOMSHEET_CLOSED).remove();
|
||||||
|
if (!$(".qor-bottomsheets").is(":visible")) {
|
||||||
|
$("body").removeClass(CLASS_OPEN);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh: function() {
|
||||||
|
this.$bottomsheets.remove();
|
||||||
|
$("body").removeClass(CLASS_OPEN);
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
window.location.reload();
|
||||||
|
}, 350);
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorBottomSheets.DEFAULTS = {
|
||||||
|
title: ".qor-form-title, .mdl-layout-title",
|
||||||
|
content: false
|
||||||
|
};
|
||||||
|
|
||||||
|
QorBottomSheets.TEMPLATE_ERROR = `<ul class="qor-error"><li><label><i class="material-icons">error</i><span>[[error]]</span></label></li></ul>`;
|
||||||
|
QorBottomSheets.TEMPLATE_LOADING = `<div style="text-align: center; margin-top: 30px;"><div class="mdl-spinner mdl-js-spinner is-active qor-layout__bottomsheet-spinner"></div></div>`;
|
||||||
|
QorBottomSheets.TEMPLATE_SEARCH = `<div class="qor-bottomsheets__search">
|
||||||
|
<input autocomplete="off" type="text" class="mdl-textfield__input qor-bottomsheets__search-input" placeholder="Search" />
|
||||||
|
<button class="mdl-button mdl-js-button mdl-button--icon qor-bottomsheets__search-button" type="button"><i class="material-icons">search</i></button>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorBottomSheets.TEMPLATE = `<div class="qor-bottomsheets">
|
||||||
|
<div class="qor-bottomsheets__header">
|
||||||
|
<h3 class="qor-bottomsheets__title"></h3>
|
||||||
|
<button type="button" class="mdl-button mdl-button--icon mdl-js-button mdl-js-repple-effect qor-bottomsheets__close" data-dismiss="bottomsheets">
|
||||||
|
<span class="material-icons">close</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="qor-bottomsheets__body"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorBottomSheets.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorBottomSheets(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === "string" && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.qorBottomSheets = QorBottomSheets.plugin;
|
||||||
|
|
||||||
|
return QorBottomSheets;
|
||||||
|
});
|
||||||
131
app/views/qor/assets/javascripts/qor/qor-chooser.js
Normal file
131
app/views/qor/assets/javascripts/qor/qor-chooser.js
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var NAMESPACE = 'qor.chooser';
|
||||||
|
var EVENT_ENABLE = 'enable.' + NAMESPACE;
|
||||||
|
var EVENT_DISABLE = 'disable.' + NAMESPACE;
|
||||||
|
|
||||||
|
function QorChooser(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorChooser.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorChooser.prototype = {
|
||||||
|
constructor: QorChooser,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
let $this = this.$element,
|
||||||
|
select2Data = $this.data(),
|
||||||
|
resetSelect2Width,
|
||||||
|
option = {
|
||||||
|
minimumResultsForSearch: 8,
|
||||||
|
dropdownParent: $this.parent()
|
||||||
|
};
|
||||||
|
let getSelect2AjaxDynamicURL = window.getSelect2AjaxDynamicURL;
|
||||||
|
let remoteImage = select2Data.remoteImage;
|
||||||
|
|
||||||
|
if (select2Data.remoteData) {
|
||||||
|
option.ajax = $.fn.select2.ajaxCommonOptions(select2Data);
|
||||||
|
if (getSelect2AjaxDynamicURL && $.isFunction(getSelect2AjaxDynamicURL)) {
|
||||||
|
option.ajax.url = function() {
|
||||||
|
return getSelect2AjaxDynamicURL(select2Data);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
option.ajax.url = select2Data.remoteUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
option.templateResult = function(data) {
|
||||||
|
let tmpl = $this.parents('.qor-field').find('[name="select2-result-template"]');
|
||||||
|
return $.fn.select2.ajaxFormatResult(data, tmpl, remoteImage);
|
||||||
|
};
|
||||||
|
|
||||||
|
option.templateSelection = function(data) {
|
||||||
|
if (data.loading) return data.text;
|
||||||
|
let tmpl = $this.parents('.qor-field').find('[name="select2-selection-template"]');
|
||||||
|
return $.fn.select2.ajaxFormatResult(data, tmpl, remoteImage);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
$this
|
||||||
|
.on('select2:select', function(evt) {
|
||||||
|
$(evt.target).attr('chooser-selected', 'true');
|
||||||
|
})
|
||||||
|
.on('select2:unselect', function(evt) {
|
||||||
|
$(evt.target).attr('chooser-selected', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
$this.select2(option);
|
||||||
|
|
||||||
|
// reset select2 container width
|
||||||
|
this.resetSelect2Width();
|
||||||
|
resetSelect2Width = window._.debounce(this.resetSelect2Width.bind(this), 300);
|
||||||
|
$(window).resize(resetSelect2Width);
|
||||||
|
|
||||||
|
if ($this.val()) {
|
||||||
|
$this.attr('chooser-selected', 'true');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resetSelect2Width: function() {
|
||||||
|
var $container,
|
||||||
|
select2 = this.$element.data().select2;
|
||||||
|
if (select2 && select2.$container) {
|
||||||
|
$container = select2.$container;
|
||||||
|
$container.width($container.parent().width());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.$element.select2('destroy').removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorChooser.DEFAULTS = {};
|
||||||
|
|
||||||
|
QorChooser.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorChooser(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = 'select[data-toggle="qor.chooser"]';
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorChooser.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorChooser.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorChooser;
|
||||||
|
});
|
||||||
218
app/views/qor/assets/javascripts/qor/qor-common.js
Normal file
218
app/views/qor/assets/javascripts/qor/qor-common.js
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
$(function() {
|
||||||
|
let _ = window._,
|
||||||
|
QOR = window.QOR,
|
||||||
|
QOR_Translations = window.QOR_Translations,
|
||||||
|
html = `<div id="dialog" style="display: none;">
|
||||||
|
<div class="mdl-dialog-bg"></div>
|
||||||
|
<div class="mdl-dialog">
|
||||||
|
<div class="mdl-dialog__content">
|
||||||
|
<p><i class="material-icons">warning</i></p>
|
||||||
|
<p class="mdl-dialog__message dialog-message">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-dialog__actions">
|
||||||
|
<button type="button" class="mdl-button mdl-button--raised mdl-button--colored dialog-ok dialog-button" data-type="confirm">
|
||||||
|
${QOR_Translations.okButton}
|
||||||
|
</button>
|
||||||
|
<button type="button" class="mdl-button dialog-cancel dialog-button" data-type="">
|
||||||
|
${QOR_Translations.cancelButton}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
$dialog = $(html).appendTo("body");
|
||||||
|
|
||||||
|
// ************************************ Refactor window.confirm ************************************
|
||||||
|
$(document)
|
||||||
|
.on("keyup.qor.confirm", function(e) {
|
||||||
|
if (!$dialog.is(":visible")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e.which === 27) {
|
||||||
|
setTimeout(function() {
|
||||||
|
$dialog.hide();
|
||||||
|
QOR.qorConfirmCallback = undefined;
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
if (e.which === 13) {
|
||||||
|
setTimeout(function() {
|
||||||
|
$('.dialog-button[data-type="confirm"]').click();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on("click.qor.confirm", ".dialog-button", function() {
|
||||||
|
let value = $(this).data("type"),
|
||||||
|
callback = QOR.qorConfirmCallback;
|
||||||
|
|
||||||
|
$.isFunction(callback) && callback(value);
|
||||||
|
$dialog.hide();
|
||||||
|
QOR.qorConfirmCallback = undefined;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
QOR.qorConfirm = function(data, callback) {
|
||||||
|
let okBtn = $dialog.find(".dialog-ok"),
|
||||||
|
cancelBtn = $dialog.find(".dialog-cancel");
|
||||||
|
|
||||||
|
if (_.isString(data)) {
|
||||||
|
$dialog.find(".dialog-message").text(data);
|
||||||
|
okBtn.text(QOR_Translations.okButton);
|
||||||
|
cancelBtn.text(QOR_Translations.cancelButton);
|
||||||
|
} else if (_.isObject(data)) {
|
||||||
|
if (data.confirmOk && data.confirmCancel) {
|
||||||
|
okBtn.text(data.confirmOk);
|
||||||
|
cancelBtn.text(data.confirmCancel);
|
||||||
|
} else {
|
||||||
|
okBtn.text(QOR_Translations.okButton);
|
||||||
|
cancelBtn.text(QOR_Translations.cancelButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.icon){
|
||||||
|
$dialog.find('i.material-icons').addClass(data.icon).html(data.icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dialog.find(".dialog-message").text(data.confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dialog.show();
|
||||||
|
QOR.qorConfirmCallback = callback;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// *******************************************************************************
|
||||||
|
|
||||||
|
// ****************Handle download file from AJAX POST****************************
|
||||||
|
let objectToFormData = function(obj, form) {
|
||||||
|
let formdata = form || new FormData(),
|
||||||
|
key;
|
||||||
|
|
||||||
|
for (var variable in obj) {
|
||||||
|
if (obj.hasOwnProperty(variable) && obj[variable]) {
|
||||||
|
key = variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj[variable] instanceof Date) {
|
||||||
|
formdata.append(key, obj[variable].toISOString());
|
||||||
|
} else if (
|
||||||
|
typeof obj[variable] === "object" &&
|
||||||
|
!(obj[variable] instanceof File)
|
||||||
|
) {
|
||||||
|
objectToFormData(obj[variable], formdata);
|
||||||
|
} else {
|
||||||
|
formdata.append(key, obj[variable]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return formdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
QOR.qorAjaxHandleFile = function(url, contentType, fileName, data) {
|
||||||
|
let request = new XMLHttpRequest();
|
||||||
|
|
||||||
|
request.responseType = "arraybuffer";
|
||||||
|
request.open("POST", url, true);
|
||||||
|
request.onload = function() {
|
||||||
|
if (this.status === 200) {
|
||||||
|
let blob = new Blob([this.response], {
|
||||||
|
type: contentType
|
||||||
|
}),
|
||||||
|
url = window.URL.createObjectURL(blob),
|
||||||
|
a = document.createElement("a");
|
||||||
|
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.href = url;
|
||||||
|
a.download = fileName || "download-" + $.now();
|
||||||
|
a.click();
|
||||||
|
} else {
|
||||||
|
window.alert(QOR_Translations.serverError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_.isObject(data)) {
|
||||||
|
if (Object.prototype.toString.call(data) != "[object FormData]") {
|
||||||
|
data = objectToFormData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
request.send(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ********************************convert video link********************
|
||||||
|
// linkyoutube: /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig,
|
||||||
|
// linkvimeo: /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/,
|
||||||
|
|
||||||
|
let converVideoLinks = function() {
|
||||||
|
let $ele = $(".qor-linkify-object"),
|
||||||
|
linkyoutube = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/gi;
|
||||||
|
|
||||||
|
if (!$ele.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ele.each(function() {
|
||||||
|
let url = $(this).data("video-link");
|
||||||
|
if (url.match(linkyoutube)) {
|
||||||
|
$(this).html(
|
||||||
|
`<iframe width="100%" height="100%" src="//www.youtube.com/embed/${url.replace(
|
||||||
|
linkyoutube,
|
||||||
|
"$1"
|
||||||
|
)}" frameborder="0" allowfullscreen></iframe>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.qorSliderAfterShow.converVideoLinks = converVideoLinks;
|
||||||
|
converVideoLinks();
|
||||||
|
|
||||||
|
// ********************************Qor Handle AJAX error********************
|
||||||
|
QOR.handleAjaxError = function(err) {
|
||||||
|
let $body = $("body"),
|
||||||
|
rJSON = err.responseJSON,
|
||||||
|
rText = err.responseText,
|
||||||
|
$error = $(`<ul class="qor-alert qor-error" data-dismissible="true"><button type="button" class="mdl-button mdl-button--icon" data-dismiss="alert">
|
||||||
|
<i class="material-icons">close</i>
|
||||||
|
</button></ul>`);
|
||||||
|
|
||||||
|
$body.find(".qor-alert").remove();
|
||||||
|
|
||||||
|
if (err.status === 422) {
|
||||||
|
if (rJSON) {
|
||||||
|
let errors = rJSON.errors,
|
||||||
|
$errorContent = "";
|
||||||
|
|
||||||
|
if ($.isArray(errors)) {
|
||||||
|
for (let i = 0; i < errors.length; i++) {
|
||||||
|
$errorContent += `<li>
|
||||||
|
<i class="material-icons">error</i>
|
||||||
|
<span>${errors[i]}</span>
|
||||||
|
</li>`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errorContent = `<li>
|
||||||
|
<i class="material-icons">error</i>
|
||||||
|
<span>${errors}</span>
|
||||||
|
</li>`;
|
||||||
|
}
|
||||||
|
$error.append($errorContent);
|
||||||
|
} else {
|
||||||
|
$error = $(rText).find(".qor-error");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error.append(`<li>
|
||||||
|
<i class="material-icons">error</i>
|
||||||
|
<span>${err.statusText}</span>
|
||||||
|
</li>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
$error.prependTo($body);
|
||||||
|
setTimeout(function() {
|
||||||
|
$error.addClass("qor-alert__active");
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
$('.qor-alert[data-dismissible="true"]').removeClass("qor-alert__active");
|
||||||
|
$("#qor-submit-loading").remove();
|
||||||
|
}, 6000);
|
||||||
|
};
|
||||||
|
});
|
||||||
126
app/views/qor/assets/javascripts/qor/qor-config.js
Normal file
126
app/views/qor/assets/javascripts/qor/qor-config.js
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
// init for slideout after show event
|
||||||
|
$.fn.qorSliderAfterShow = $.fn.qorSliderAfterShow || {};
|
||||||
|
window.QOR = {
|
||||||
|
$formLoading: '<div id="qor-submit-loading" class="clearfix"><div class="mdl-spinner mdl-spinner--single-color mdl-js-spinner is-active"></div></div>'
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.escapeSymbol = function() {
|
||||||
|
var tagsToReplace = {
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'"' : '"',
|
||||||
|
"'" : ''',
|
||||||
|
'/' : '/'
|
||||||
|
};
|
||||||
|
return this.replace(/[&<>"']/g, function(tag) {
|
||||||
|
return tagsToReplace[tag] || tag;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// change Mustache tags from {{}} to [[]]
|
||||||
|
window.Mustache && (window.Mustache.tags = ['[[', ']]']);
|
||||||
|
|
||||||
|
// clear close alert after ajax complete
|
||||||
|
$(document).ajaxComplete(function(event, xhr, settings) {
|
||||||
|
if (settings.type == 'POST' || settings.type == 'PUT') {
|
||||||
|
if ($.fn.qorSlideoutBeforeHide) {
|
||||||
|
$.fn.qorSlideoutBeforeHide = null;
|
||||||
|
window.onbeforeunload = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// select2 ajax common options
|
||||||
|
// $.fn.select2 = $.fn.select2 || function(){};
|
||||||
|
$.fn.select2.ajaxCommonOptions = function(select2Data) {
|
||||||
|
let remoteDataPrimaryKey = select2Data.remoteDataPrimaryKey;
|
||||||
|
|
||||||
|
return {
|
||||||
|
dataType: 'json',
|
||||||
|
headers: getSelect2Header(select2Data),
|
||||||
|
cache: true,
|
||||||
|
delay: 250,
|
||||||
|
data: function(params) {
|
||||||
|
return {
|
||||||
|
keyword: params.term, // search term
|
||||||
|
page: params.page,
|
||||||
|
per_page: 20
|
||||||
|
};
|
||||||
|
},
|
||||||
|
processResults: function(data, params) {
|
||||||
|
// parse the results into the format expected by Select2
|
||||||
|
// since we are using custom formatting functions we do not need to
|
||||||
|
// alter the remote JSON data, except to indicate that infinite
|
||||||
|
// scrolling can be used
|
||||||
|
params.page = params.page || 1;
|
||||||
|
|
||||||
|
var processedData = $.map(data, function(obj) {
|
||||||
|
obj.id = obj[remoteDataPrimaryKey] || obj.primaryKey || obj.Id || obj.ID;
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
results: processedData,
|
||||||
|
pagination: {
|
||||||
|
more: processedData.length >= 20
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// select2 ajax common options
|
||||||
|
// format ajax template data
|
||||||
|
$.fn.select2.ajaxFormatResult = function(data, tmpl, remoteDataImage) {
|
||||||
|
var result = '';
|
||||||
|
|
||||||
|
if (data.loading) {
|
||||||
|
return data.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('select2.ajaxFormatResult: Data');
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
console.log('select2.ajaxFormatResult: has remote image');
|
||||||
|
console.log(remoteDataImage);
|
||||||
|
|
||||||
|
if (remoteDataImage) {
|
||||||
|
var resultName = data.text || data.Name || data.Title || data.Code || data[Object.keys(data)[0]];
|
||||||
|
var imageUrl = data.Image;
|
||||||
|
if (imageUrl) {
|
||||||
|
result = '<div class="select2-results__option-withimage">' + '<img src="' + imageUrl + '">' + '<span>' + resultName + '</span></div>';
|
||||||
|
} else {
|
||||||
|
result = '<div class="select2-results__option-withimage">' + resultName + '</span></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $(result);
|
||||||
|
} else {
|
||||||
|
if (tmpl.length > 0) {
|
||||||
|
result = window.Mustache.render(tmpl.html().replace(/{{(.*?)}}/g, '[[$1]]'), data);
|
||||||
|
} else {
|
||||||
|
result = data.text || data.Name || data.Title || data.Code || data[Object.keys(data)[0]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// if is HTML
|
||||||
|
if (/<(.*)(\/>|<\/.+>)/.test(result)) {
|
||||||
|
return $(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getSelect2Header() {
|
||||||
|
let data = $('body').data();
|
||||||
|
let selectAjaxHeader = data.selectAjaxHeader;
|
||||||
|
let getSelect2HeaderFunction = window.getSelect2HeaderFunction;
|
||||||
|
let headers = {};
|
||||||
|
|
||||||
|
if (selectAjaxHeader && getSelect2HeaderFunction && $.isFunction(getSelect2HeaderFunction)) {
|
||||||
|
headers[selectAjaxHeader] = getSelect2HeaderFunction();
|
||||||
|
return headers;
|
||||||
|
} else {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
766
app/views/qor/assets/javascripts/qor/qor-cropper.js
Normal file
766
app/views/qor/assets/javascripts/qor/qor-cropper.js
Normal file
@@ -0,0 +1,766 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let URL = window.URL || window.webkitURL,
|
||||||
|
NAMESPACE = 'qor.cropper',
|
||||||
|
// Events
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_CHANGE = 'change.' + NAMESPACE,
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
EVENT_SHOWN = 'shown.qor.modal',
|
||||||
|
EVENT_HIDDEN = 'hidden.qor.modal',
|
||||||
|
// Classes
|
||||||
|
CLASS_TOGGLE = '.qor-cropper__toggle',
|
||||||
|
CLASS_CANVAS = '.qor-cropper__canvas',
|
||||||
|
CLASS_WRAPPER = '.qor-cropper__wrapper',
|
||||||
|
CLASS_OPTIONS = '.qor-cropper__options',
|
||||||
|
CLASS_SAVE = '.qor-cropper__save',
|
||||||
|
CLASS_DELETE = '.qor-cropper__toggle--delete',
|
||||||
|
CLASS_CROP = '.qor-cropper__toggle--crop',
|
||||||
|
CLASS_UNDO = '.qor-fieldset__undo',
|
||||||
|
HIDDEN_DATA_INPUT = 'input[name="QorResource.MediaOption"]:hidden';
|
||||||
|
|
||||||
|
function capitalize(str) {
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
str = str.charAt(0).toUpperCase() + str.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLowerCaseKeyObject(obj) {
|
||||||
|
let newObj = {},
|
||||||
|
key;
|
||||||
|
|
||||||
|
if ($.isPlainObject(obj)) {
|
||||||
|
for (key in obj) {
|
||||||
|
if (obj.hasOwnProperty(key)) {
|
||||||
|
newObj[String(key).toLowerCase()] = obj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValueByNoCaseKey(obj, key) {
|
||||||
|
let originalKey = String(key),
|
||||||
|
lowerCaseKey = originalKey.toLowerCase(),
|
||||||
|
upperCaseKey = originalKey.toUpperCase(),
|
||||||
|
capitalizeKey = capitalize(originalKey);
|
||||||
|
|
||||||
|
if ($.isPlainObject(obj)) {
|
||||||
|
return obj[lowerCaseKey] || obj[capitalizeKey] || obj[upperCaseKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceText(str, data) {
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
if (typeof data === 'object') {
|
||||||
|
$.each(data, function(key, val) {
|
||||||
|
str = str.replace('$[' + String(key).toLowerCase() + ']', val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSVG(url) {
|
||||||
|
return /.svg$/.test(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function QorCropper(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend(true, {}, QorCropper.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.data = null;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorCropper.prototype = {
|
||||||
|
constructor: QorCropper,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
let options = this.options,
|
||||||
|
$this = this.$element,
|
||||||
|
$parent = $this.closest(options.parent),
|
||||||
|
data,
|
||||||
|
outputValue,
|
||||||
|
fetchUrl,
|
||||||
|
_this = this,
|
||||||
|
imageData;
|
||||||
|
|
||||||
|
if (!$parent.length) {
|
||||||
|
$parent = $this.parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$parent = $parent;
|
||||||
|
this.$output = $parent.find(options.output);
|
||||||
|
this.$formCropInput = $parent.closest('form').find(HIDDEN_DATA_INPUT);
|
||||||
|
this.$list = $parent.find(options.list);
|
||||||
|
|
||||||
|
fetchUrl = this.$output.data('fetchSizedata');
|
||||||
|
|
||||||
|
if (fetchUrl) {
|
||||||
|
$.getJSON(fetchUrl, function(data) {
|
||||||
|
imageData = JSON.parse(data.MediaOption);
|
||||||
|
_this.$output.val(JSON.stringify(data));
|
||||||
|
_this.$formCropInput.val(JSON.stringify(data));
|
||||||
|
_this.data = imageData || {};
|
||||||
|
if (isSVG(imageData.URL || imageData.Url)) {
|
||||||
|
_this.resetImage();
|
||||||
|
}
|
||||||
|
_this.build();
|
||||||
|
_this.bind();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
outputValue = $.trim(this.$output.val());
|
||||||
|
if (outputValue) {
|
||||||
|
data = JSON.parse(outputValue);
|
||||||
|
if (isSVG(data.URL || data.Url)) {
|
||||||
|
this.resetImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data = data || {};
|
||||||
|
|
||||||
|
this.build();
|
||||||
|
this.bind();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resetImage: function() {
|
||||||
|
this.$parent.addClass('is-svg');
|
||||||
|
},
|
||||||
|
|
||||||
|
build: function() {
|
||||||
|
let textData = this.$output.data(),
|
||||||
|
text = {},
|
||||||
|
replaceTexts;
|
||||||
|
|
||||||
|
if (textData) {
|
||||||
|
text = {
|
||||||
|
title: textData.cropperTitle,
|
||||||
|
ok: textData.cropperOk,
|
||||||
|
cancel: textData.cropperCancel
|
||||||
|
};
|
||||||
|
replaceTexts = this.options.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.ok && text.title && text.cancel) {
|
||||||
|
replaceTexts = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.wrap();
|
||||||
|
this.$modal = $(replaceText(QorCropper.MODAL, replaceTexts)).appendTo('body');
|
||||||
|
},
|
||||||
|
|
||||||
|
unbuild: function() {
|
||||||
|
this.$modal.remove();
|
||||||
|
this.unwrap();
|
||||||
|
},
|
||||||
|
|
||||||
|
wrap: function() {
|
||||||
|
let $list = this.$list,
|
||||||
|
$img;
|
||||||
|
|
||||||
|
$img = $list.find('img').not('.is-svg');
|
||||||
|
|
||||||
|
if ($img.length) {
|
||||||
|
$list.find('li').append(QorCropper.TOGGLE);
|
||||||
|
$img.wrap(QorCropper.CANVAS);
|
||||||
|
this.center($img);
|
||||||
|
} else {
|
||||||
|
$list.find(CLASS_CROP).remove();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
unwrap: function() {
|
||||||
|
let $list = this.$list;
|
||||||
|
|
||||||
|
$list.find(CLASS_TOGGLE).remove();
|
||||||
|
$list.find(CLASS_CANVAS).each(function() {
|
||||||
|
let $this = $(this);
|
||||||
|
|
||||||
|
$this.before($this.html()).remove();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$element.on(EVENT_CHANGE, $.proxy(this.read, this));
|
||||||
|
this.$list.on(EVENT_CLICK, $.proxy(this.click, this));
|
||||||
|
this.$modal.on(EVENT_SHOWN, $.proxy(this.start, this)).on(EVENT_HIDDEN, $.proxy(this.stop, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element.off(EVENT_CHANGE, this.read);
|
||||||
|
this.$list.off(EVENT_CLICK, this.click);
|
||||||
|
this.$modal.off(EVENT_SHOWN, this.start).off(EVENT_HIDDEN, this.stop);
|
||||||
|
},
|
||||||
|
|
||||||
|
click: function(e) {
|
||||||
|
let target = e.target,
|
||||||
|
$target,
|
||||||
|
data = this.data,
|
||||||
|
$alert;
|
||||||
|
|
||||||
|
if (target === this.$list[0]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$target = $(target);
|
||||||
|
|
||||||
|
if ($target.closest(CLASS_DELETE).length) {
|
||||||
|
data.Delete = true;
|
||||||
|
|
||||||
|
this.$output.val(JSON.stringify(data));
|
||||||
|
this.$formCropInput.val(JSON.stringify(data));
|
||||||
|
|
||||||
|
this.$list.hide();
|
||||||
|
|
||||||
|
$alert = $(QorCropper.ALERT);
|
||||||
|
$alert.find(CLASS_UNDO).one(
|
||||||
|
EVENT_CLICK,
|
||||||
|
function() {
|
||||||
|
$alert.remove();
|
||||||
|
this.$list.show();
|
||||||
|
delete data.Delete;
|
||||||
|
this.$output.val(JSON.stringify(data));
|
||||||
|
this.$formCropInput.val(JSON.stringify(data));
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
this.$parent.find('.qor-fieldset').append($alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target.closest(CLASS_CROP).length) {
|
||||||
|
$target = $target.closest('li').find('img');
|
||||||
|
this.$target = $target;
|
||||||
|
this.$modal.qorModal('show');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
read: function(e) {
|
||||||
|
let files = e.target.files,
|
||||||
|
file,
|
||||||
|
$list = this.$list,
|
||||||
|
$alert = this.$parent.find('.qor-fieldset__alert');
|
||||||
|
|
||||||
|
$list.show();
|
||||||
|
|
||||||
|
if ($alert.length) {
|
||||||
|
$alert.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files && files.length) {
|
||||||
|
file = files[0];
|
||||||
|
|
||||||
|
if (/^image\//.test(file.type) && URL) {
|
||||||
|
this.fileType = file.type;
|
||||||
|
this.load(URL.createObjectURL(file));
|
||||||
|
this.$parent.find('.qor-medialibrary__image-desc').show();
|
||||||
|
} else {
|
||||||
|
$list.empty().html(QorCropper.FILE_LIST.replace('{{filename}}', file.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
load: function(url, fromExternal, callback) {
|
||||||
|
let options = this.options,
|
||||||
|
_this = this,
|
||||||
|
$list = this.$list,
|
||||||
|
$ul = $(QorCropper.LIST),
|
||||||
|
data = this.data || {},
|
||||||
|
outputOriginalData = this.$output.val() ? JSON.parse(this.$output.val()) : {},
|
||||||
|
outputOriginalDataType = ['Video', 'SelectedType', 'Description'],
|
||||||
|
fileType = this.fileType,
|
||||||
|
$image,
|
||||||
|
imageLength;
|
||||||
|
|
||||||
|
// media box will use load method, has it's own html structure.
|
||||||
|
if (!fromExternal) {
|
||||||
|
$list.find('ul').remove();
|
||||||
|
$list.html($ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
$image = $list.find('img');
|
||||||
|
this.wrap();
|
||||||
|
|
||||||
|
imageLength = $image.length;
|
||||||
|
$image
|
||||||
|
.one('load', function() {
|
||||||
|
if (fileType === 'image/svg+xml') {
|
||||||
|
$list.find(CLASS_TOGGLE).remove();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let $this = $(this),
|
||||||
|
naturalWidth = this.naturalWidth,
|
||||||
|
naturalHeight = this.naturalHeight,
|
||||||
|
sizeData = $this.data(),
|
||||||
|
sizeResolution = sizeData.sizeResolution,
|
||||||
|
sizeName = sizeData.sizeName,
|
||||||
|
emulateImageData = {},
|
||||||
|
emulateCropData = {},
|
||||||
|
aspectRatio,
|
||||||
|
width = sizeData.sizeResolutionWidth,
|
||||||
|
height = sizeData.sizeResolutionHeight;
|
||||||
|
|
||||||
|
if (sizeResolution) {
|
||||||
|
if (!width && !height) {
|
||||||
|
width = getValueByNoCaseKey(sizeResolution, 'width');
|
||||||
|
height = getValueByNoCaseKey(sizeResolution, 'height');
|
||||||
|
}
|
||||||
|
if (height && width) {
|
||||||
|
aspectRatio = width / height;
|
||||||
|
} else {
|
||||||
|
aspectRatio = naturalWidth / naturalHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (naturalHeight * aspectRatio > naturalWidth) {
|
||||||
|
width = naturalWidth;
|
||||||
|
height = width / aspectRatio;
|
||||||
|
} else {
|
||||||
|
height = naturalHeight;
|
||||||
|
width = height * aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
emulateImageData = {
|
||||||
|
naturalWidth: naturalWidth,
|
||||||
|
naturalHeight: naturalHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
emulateCropData = {
|
||||||
|
x: Math.round((naturalWidth - width) / 2),
|
||||||
|
y: Math.round((naturalHeight - height) / 2),
|
||||||
|
width: Math.round(width),
|
||||||
|
height: Math.round(height)
|
||||||
|
};
|
||||||
|
|
||||||
|
_this.preview($this, emulateImageData, emulateCropData);
|
||||||
|
|
||||||
|
if (sizeName) {
|
||||||
|
data.Crop = true;
|
||||||
|
|
||||||
|
if (!data[options.key]) {
|
||||||
|
data[options.key] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sizeName != 'original') {
|
||||||
|
data[options.key][sizeName] = emulateCropData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_this.center($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crop, CropOptions and Delete should be BOOL type, if empty should delete,
|
||||||
|
if (data.Crop === '' || !fromExternal) {
|
||||||
|
delete data.Crop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fromExternal) {
|
||||||
|
data.CropOptions = null;
|
||||||
|
delete data.Sizes;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete data.Delete;
|
||||||
|
|
||||||
|
// Fix media upload image other property missing bug: ["Video", "SelectedType", "Description"]
|
||||||
|
outputOriginalDataType.forEach((type) => {
|
||||||
|
if (outputOriginalData[type]) {
|
||||||
|
data[type] = outputOriginalData[type];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_this.$output.val(JSON.stringify(data));
|
||||||
|
_this.$formCropInput.val(JSON.stringify(data));
|
||||||
|
|
||||||
|
// callback after load complete
|
||||||
|
if (sizeName && data[options.key] && Object.keys(data[options.key]).length >= imageLength) {
|
||||||
|
if (callback && $.isFunction(callback)) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.attr('src', url)
|
||||||
|
.data('originalUrl', url);
|
||||||
|
|
||||||
|
$list.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
start: function() {
|
||||||
|
let options = this.options,
|
||||||
|
$modal = this.$modal,
|
||||||
|
$target = this.$target,
|
||||||
|
sizeData = $target.data(),
|
||||||
|
sizeName = sizeData.sizeName || 'original',
|
||||||
|
sizeResolution = sizeData.sizeResolution,
|
||||||
|
originalUrl = (sizeData && sizeData.originalUrl && $target.attr('data-original-url'))
|
||||||
|
? (/\.original\./.test(sizeData.originalUrl) ? sizeData.originalUrl
|
||||||
|
: /\.original\./.test($target.attr('data-original-url'))
|
||||||
|
? $target.attr('data-original-url')
|
||||||
|
: $target.attr('data-original-url').replace(/file\./, 'file.original.'))
|
||||||
|
: $target.attr('src'),
|
||||||
|
$clone = $(`<img src=${originalUrl}>`),
|
||||||
|
data = this.data || {},
|
||||||
|
_this = this,
|
||||||
|
sizeAspectRatio = NaN,
|
||||||
|
sizeWidth = sizeData.sizeResolutionWidth,
|
||||||
|
sizeHeight = sizeData.sizeResolutionHeight,
|
||||||
|
list;
|
||||||
|
|
||||||
|
if (sizeResolution) {
|
||||||
|
if (!sizeWidth && !sizeHeight) {
|
||||||
|
sizeWidth = getValueByNoCaseKey(sizeResolution, 'width');
|
||||||
|
sizeHeight = getValueByNoCaseKey(sizeResolution, 'height');
|
||||||
|
}
|
||||||
|
sizeAspectRatio = sizeWidth / sizeHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data[options.key]) {
|
||||||
|
data[options.key] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
$modal
|
||||||
|
.trigger('enable.qor.material')
|
||||||
|
.find(CLASS_WRAPPER)
|
||||||
|
.html($clone);
|
||||||
|
|
||||||
|
list = this.getList(sizeAspectRatio);
|
||||||
|
|
||||||
|
if (list) {
|
||||||
|
$modal
|
||||||
|
.find(CLASS_OPTIONS)
|
||||||
|
.show()
|
||||||
|
.append(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
$clone.cropper({
|
||||||
|
aspectRatio: sizeAspectRatio,
|
||||||
|
data: getLowerCaseKeyObject(data[options.key][sizeName]),
|
||||||
|
background: false,
|
||||||
|
movable: false,
|
||||||
|
zoomable: false,
|
||||||
|
scalable: false,
|
||||||
|
rotatable: false,
|
||||||
|
autoCropArea: 1,
|
||||||
|
|
||||||
|
ready: function() {
|
||||||
|
$modal
|
||||||
|
.find('.qor-cropper__options-toggle')
|
||||||
|
.on(EVENT_CLICK, function() {
|
||||||
|
$modal.find('.qor-cropper__options-input').prop('checked', $(this).prop('checked'));
|
||||||
|
})
|
||||||
|
.prop('checked', true);
|
||||||
|
|
||||||
|
$modal.find(CLASS_SAVE).one(EVENT_CLICK, function() {
|
||||||
|
let cropData = $clone.cropper('getData', true),
|
||||||
|
croppedCanvas = $clone.cropper('getCroppedCanvas'),
|
||||||
|
syncData = [],
|
||||||
|
url;
|
||||||
|
|
||||||
|
data.Crop = true;
|
||||||
|
data[options.key][sizeName] = cropData;
|
||||||
|
_this.imageData = $clone.cropper('getImageData');
|
||||||
|
_this.cropData = cropData;
|
||||||
|
|
||||||
|
if (croppedCanvas) {
|
||||||
|
try {
|
||||||
|
url = croppedCanvas.toDataURL();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
console.log('Please check image Cross-origin setting');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$modal.find(CLASS_OPTIONS + ' input').each(function() {
|
||||||
|
let $this = $(this);
|
||||||
|
|
||||||
|
if ($this.prop('checked')) {
|
||||||
|
syncData.push($this.attr('name'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_this.output(url, syncData);
|
||||||
|
$modal.qorModal('hide');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
stop: function() {
|
||||||
|
this.$modal
|
||||||
|
.trigger('disable.qor.material')
|
||||||
|
.find(CLASS_WRAPPER + ' > img')
|
||||||
|
.cropper('destroy')
|
||||||
|
.remove()
|
||||||
|
.end()
|
||||||
|
.find(CLASS_OPTIONS)
|
||||||
|
.hide()
|
||||||
|
.find('ul')
|
||||||
|
.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
getList: function(aspectRatio) {
|
||||||
|
let list = [];
|
||||||
|
|
||||||
|
this.$list
|
||||||
|
.find('img')
|
||||||
|
.not(this.$target)
|
||||||
|
.each(function() {
|
||||||
|
let data = $(this).data(),
|
||||||
|
resolution = data.sizeResolution,
|
||||||
|
name = data.sizeName,
|
||||||
|
width = data.sizeResolutionWidth,
|
||||||
|
height = data.sizeResolutionHeight;
|
||||||
|
|
||||||
|
if (resolution) {
|
||||||
|
if (!width && !height) {
|
||||||
|
width = getValueByNoCaseKey(resolution, 'width');
|
||||||
|
height = getValueByNoCaseKey(resolution, 'height');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width / height === aspectRatio) {
|
||||||
|
list.push(
|
||||||
|
'<label>' +
|
||||||
|
'<input class="qor-cropper__options-input" type="checkbox" name="' +
|
||||||
|
name +
|
||||||
|
'" checked> ' +
|
||||||
|
'<span>' +
|
||||||
|
name +
|
||||||
|
'<small>(' +
|
||||||
|
width +
|
||||||
|
'×' +
|
||||||
|
height +
|
||||||
|
' px)</small>' +
|
||||||
|
'</span>' +
|
||||||
|
'</label>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return list.length ? '<ul><li>' + list.join('</li><li>') + '</li></ul>' : '';
|
||||||
|
},
|
||||||
|
|
||||||
|
output: function(url, data) {
|
||||||
|
let $target = this.$target;
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
this.center($target.attr('src', url), true);
|
||||||
|
} else {
|
||||||
|
this.preview($target);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($.isArray(data) && data.length) {
|
||||||
|
this.autoCrop(url, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$output.val(JSON.stringify(this.data)).trigger(EVENT_CHANGE);
|
||||||
|
this.$formCropInput.val(JSON.stringify(this.data));
|
||||||
|
},
|
||||||
|
|
||||||
|
preview: function($target, emulateImageData, emulateCropData) {
|
||||||
|
let $canvas = $target.parent(),
|
||||||
|
$container = $canvas.parent(),
|
||||||
|
containerWidth = $container.width(),
|
||||||
|
containerHeight = $container.height(),
|
||||||
|
imageData = emulateImageData || this.imageData,
|
||||||
|
cropData = $.extend({}, emulateCropData || this.cropData), // Clone one to avoid changing it
|
||||||
|
aspectRatio = cropData.width / cropData.height,
|
||||||
|
canvasWidth = containerWidth,
|
||||||
|
scaledRatio;
|
||||||
|
|
||||||
|
if (canvasWidth == 0 || imageData.naturalWidth == 0 || imageData.naturalHeight == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containerHeight * aspectRatio <= containerWidth) {
|
||||||
|
canvasWidth = containerHeight * aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
scaledRatio = cropData.width / canvasWidth;
|
||||||
|
|
||||||
|
$target.css({
|
||||||
|
maxWidth: imageData.naturalWidth / scaledRatio,
|
||||||
|
maxHeight: imageData.naturalHeight / scaledRatio
|
||||||
|
});
|
||||||
|
|
||||||
|
this.center($target);
|
||||||
|
},
|
||||||
|
|
||||||
|
center: function($target, reset) {
|
||||||
|
$target.each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
$canvas = $this.parent(),
|
||||||
|
$container = $canvas.parent();
|
||||||
|
|
||||||
|
function center() {
|
||||||
|
let containerHeight = $container.height(),
|
||||||
|
canvasHeight = $canvas.height(),
|
||||||
|
marginTop = 'auto';
|
||||||
|
|
||||||
|
if (canvasHeight < containerHeight) {
|
||||||
|
marginTop = (containerHeight - canvasHeight) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$canvas.css('margin-top', marginTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset) {
|
||||||
|
$canvas.add($this).removeAttr('style');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.complete) {
|
||||||
|
center.call(this);
|
||||||
|
} else {
|
||||||
|
this.onload = center;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
autoCrop: function(url, data) {
|
||||||
|
let cropData = this.cropData,
|
||||||
|
cropOptions = this.data[this.options.key],
|
||||||
|
_this = this;
|
||||||
|
|
||||||
|
this.$list
|
||||||
|
.find('img')
|
||||||
|
.not(this.$target)
|
||||||
|
.each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
sizeName = $this.data('sizeName');
|
||||||
|
|
||||||
|
if ($.inArray(sizeName, data) > -1) {
|
||||||
|
cropOptions[sizeName] = $.extend({}, cropData);
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
_this.center($this.attr('src', url), true);
|
||||||
|
} else {
|
||||||
|
_this.preview($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
if (!isSVG) {
|
||||||
|
this.unbind();
|
||||||
|
this.unbuild();
|
||||||
|
}
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorCropper.DEFAULTS = {
|
||||||
|
parent: false,
|
||||||
|
output: false,
|
||||||
|
list: false,
|
||||||
|
key: 'data',
|
||||||
|
data: null,
|
||||||
|
text: {
|
||||||
|
title: 'Crop the image',
|
||||||
|
ok: 'OK',
|
||||||
|
cancel: 'Cancel'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorCropper.TOGGLE = `<div class="qor-cropper__toggle">
|
||||||
|
<div class="qor-cropper__toggle--crop"><i class="material-icons">crop</i></div>
|
||||||
|
<div class="qor-cropper__toggle--delete"><i class="material-icons">delete</i></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorCropper.ALERT = `<div class="qor-fieldset__alert">
|
||||||
|
<button class="mdl-button mdl-button--accent qor-fieldset__undo" type="button">Undo delete</button>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorCropper.CANVAS = '<div class="qor-cropper__canvas"></div>';
|
||||||
|
QorCropper.LIST = '<ul><li><img></li></ul>';
|
||||||
|
QorCropper.FILE_LIST = `<div class="qor-file__list-item">
|
||||||
|
<span><span>{{filename}}</span></span>
|
||||||
|
<div class="qor-cropper__toggle">
|
||||||
|
<div class="qor-cropper__toggle--delete"><i class="material-icons">delete</i></div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
QorCropper.MODAL = `<div class="qor-modal fade" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div class="mdl-card mdl-shadow--2dp" role="document">
|
||||||
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">$[title]</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting-text">
|
||||||
|
<div class="qor-cropper__wrapper"></div>
|
||||||
|
<div class="qor-cropper__options">
|
||||||
|
<p>Sync cropping result to: <label><input type="checkbox" class="qor-cropper__options-toggle" checked/> All</label></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__actions mdl-card--border">
|
||||||
|
<a class="mdl-button mdl-button--colored mdl-button--raised qor-cropper__save">$[ok]</a>
|
||||||
|
<a class="mdl-button mdl-button--colored" data-dismiss="modal">$[cancel]</a>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__menu">
|
||||||
|
<button class="mdl-button mdl-button--icon" data-dismiss="modal" aria-label="close">
|
||||||
|
<i class="material-icons">close</i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorCropper.plugin = function(option) {
|
||||||
|
return this.each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
data = $this.data(NAMESPACE),
|
||||||
|
options,
|
||||||
|
fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (!$.fn.cropper) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/destroy/.test(option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
options = $.extend(true, {}, $this.data(), typeof option === 'object' && option);
|
||||||
|
$this.data(NAMESPACE, (data = new QorCropper(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof option === 'string' && $.isFunction((fn = data[option]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
let selector = '.qor-file__input',
|
||||||
|
options = {
|
||||||
|
parent: '.qor-file',
|
||||||
|
output: '.qor-file__options',
|
||||||
|
list: '.qor-file__list',
|
||||||
|
key: 'CropOptions'
|
||||||
|
};
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorCropper.plugin.call($(selector, e.target), options);
|
||||||
|
})
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorCropper.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorCropper;
|
||||||
|
});
|
||||||
242
app/views/qor/assets/javascripts/qor/qor-datepicker.js
Normal file
242
app/views/qor/assets/javascripts/qor/qor-datepicker.js
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let NAMESPACE = 'qor.datepicker',
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_CHANGE = 'pick.' + NAMESPACE,
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
CLASS_EMBEDDED = '.qor-datepicker__embedded',
|
||||||
|
CLASS_SAVE = '.qor-datepicker__save',
|
||||||
|
CLASS_PARENT = '[data-picker-type]';
|
||||||
|
|
||||||
|
function replaceText(str, data) {
|
||||||
|
if (typeof str === 'string') {
|
||||||
|
if (typeof data === 'object') {
|
||||||
|
$.each(data, function(key, val) {
|
||||||
|
str = str.replace('$[' + String(key).toLowerCase() + ']', val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function QorDatepicker(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend(true, {}, QorDatepicker.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.date = null;
|
||||||
|
this.formatDate = null;
|
||||||
|
this.built = false;
|
||||||
|
this.pickerData = this.$element.data();
|
||||||
|
this.$parent = this.$element.closest(CLASS_PARENT);
|
||||||
|
this.isDateTimePicker = this.$parent.data('picker-type') == 'datetime';
|
||||||
|
this.$targetInput = this.$parent.find(this.pickerData.targetInput || (this.isDateTimePicker ? '.qor-datetimepicker__input' : '.qor-datepicker__input'));
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorDatepicker.prototype = {
|
||||||
|
init: function() {
|
||||||
|
if (this.$targetInput.is(':disabled')) {
|
||||||
|
this.$element.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$element.on(EVENT_CLICK, $.proxy(this.show, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element.off(EVENT_CLICK, this.show);
|
||||||
|
},
|
||||||
|
|
||||||
|
build: function() {
|
||||||
|
let $modal,
|
||||||
|
$ele = this.$element,
|
||||||
|
$targetInput = this.$targetInput,
|
||||||
|
defaultDate = $targetInput.val(),
|
||||||
|
datepickerOptions = {
|
||||||
|
date: new Date(),
|
||||||
|
inline: true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.built) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ele.is(':input') && Date.parse($ele.val())) {
|
||||||
|
datepickerOptions.date = new Date($ele.val());
|
||||||
|
} else if (defaultDate && Date.parse(defaultDate)) {
|
||||||
|
datepickerOptions.date = new Date(defaultDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$modal = $modal = $(replaceText(QorDatepicker.TEMPLATE, this.options.text)).appendTo('body');
|
||||||
|
|
||||||
|
if ($targetInput.data('start-date')) {
|
||||||
|
datepickerOptions.startDate = new Date($targetInput.data('start-date'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($targetInput.data('end-date')) {
|
||||||
|
datepickerOptions.endDate = new Date($targetInput.data('end-date'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$modal
|
||||||
|
.find(CLASS_EMBEDDED)
|
||||||
|
.on(EVENT_CHANGE, $.proxy(this.change, this))
|
||||||
|
.qorDatepicker(datepickerOptions)
|
||||||
|
.triggerHandler(EVENT_CHANGE);
|
||||||
|
|
||||||
|
$modal.find(CLASS_SAVE).on(EVENT_CLICK, $.proxy(this.pick, this));
|
||||||
|
|
||||||
|
this.built = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
unbuild: function() {
|
||||||
|
if (!this.built) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$modal
|
||||||
|
.find(CLASS_EMBEDDED)
|
||||||
|
.off(EVENT_CHANGE, this.change)
|
||||||
|
.qorDatepicker('destroy')
|
||||||
|
.end()
|
||||||
|
.find(CLASS_SAVE)
|
||||||
|
.off(EVENT_CLICK, this.pick)
|
||||||
|
.end()
|
||||||
|
.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
change: function(e) {
|
||||||
|
var $modal = this.$modal;
|
||||||
|
var $target = $(e.target);
|
||||||
|
var date;
|
||||||
|
|
||||||
|
this.date = date = $target.qorDatepicker('getDate');
|
||||||
|
this.formatDate = $target.qorDatepicker('getDate', true);
|
||||||
|
|
||||||
|
$modal.find('.qor-datepicker__picked-year').text(date.getFullYear());
|
||||||
|
$modal
|
||||||
|
.find('.qor-datepicker__picked-date')
|
||||||
|
.text(
|
||||||
|
[$target.qorDatepicker('getDayName', date.getDay(), true) + ',', String($target.qorDatepicker('getMonthName', date.getMonth(), true)), date.getDate()].join(' ')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function() {
|
||||||
|
if (!this.built) {
|
||||||
|
this.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$modal.qorModal('show');
|
||||||
|
},
|
||||||
|
|
||||||
|
pick: function() {
|
||||||
|
let $targetInput = this.$targetInput,
|
||||||
|
newValue = this.formatDate;
|
||||||
|
|
||||||
|
if (this.isDateTimePicker) {
|
||||||
|
var regDate = /^\d{4}-\d{1,2}-\d{1,2}/;
|
||||||
|
var oldValue = $targetInput.val();
|
||||||
|
var hasDate = regDate.test(oldValue);
|
||||||
|
|
||||||
|
if (hasDate) {
|
||||||
|
newValue = oldValue.replace(regDate, newValue);
|
||||||
|
} else {
|
||||||
|
newValue = newValue + ' 00:00';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetInput.val(newValue).trigger('change');
|
||||||
|
this.$modal.qorModal('hide');
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.unbuild();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorDatepicker.DEFAULTS = {
|
||||||
|
text: {
|
||||||
|
title: 'Pick a date',
|
||||||
|
ok: 'OK',
|
||||||
|
cancel: 'Cancel'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorDatepicker.TEMPLATE = `<div class="qor-modal fade qor-datepicker" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div class="mdl-card mdl-shadow--2dp" role="document">
|
||||||
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">$[title]</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting-text">
|
||||||
|
<div class="qor-datepicker__picked">
|
||||||
|
<div class="qor-datepicker__picked-year"></div>
|
||||||
|
<div class="qor-datepicker__picked-date"></div>
|
||||||
|
</div>
|
||||||
|
<div class="qor-datepicker__embedded"></div>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__actions">
|
||||||
|
<a class="mdl-button mdl-button--colored mdl-button--raised qor-datepicker__save">$[ok]</a>
|
||||||
|
<a class="mdl-button mdl-button--colored " data-dismiss="modal">$[cancel]</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorDatepicker.plugin = function(option) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var options;
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (!$.fn.qorDatepicker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/destroy/.test(option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
options = $.extend(true, {}, $this.data(), typeof option === 'object' && option);
|
||||||
|
$this.data(NAMESPACE, (data = new QorDatepicker(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof option === 'string' && $.isFunction((fn = data[option]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = '[data-toggle="qor.datepicker"]';
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorDatepicker.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorDatepicker.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorDatepicker;
|
||||||
|
});
|
||||||
106
app/views/qor/assets/javascripts/qor/qor-dirtyform.js
Normal file
106
app/views/qor/assets/javascripts/qor/qor-dirtyform.js
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var dirtyForm = function(ele, options) {
|
||||||
|
var hasChangedObj = false;
|
||||||
|
|
||||||
|
if (this instanceof jQuery) {
|
||||||
|
options = ele;
|
||||||
|
ele = this;
|
||||||
|
} else if (!(ele instanceof jQuery)) {
|
||||||
|
ele = $(ele);
|
||||||
|
}
|
||||||
|
|
||||||
|
ele.each(function(item, element) {
|
||||||
|
var $ele = $(element);
|
||||||
|
|
||||||
|
if ($ele.is('form')) {
|
||||||
|
if ($ele.hasClass('ignore-dirtyform')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
hasChangedObj = dirtyForm(
|
||||||
|
$ele.find(
|
||||||
|
'input:not([type="hidden"]):not(".search-field input"):not(".chosen-search input"):not(".ignore-dirtyform"), textarea, select'
|
||||||
|
),
|
||||||
|
options
|
||||||
|
);
|
||||||
|
if (hasChangedObj) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if ($ele.is(':checkbox') || $ele.is(':radio')) {
|
||||||
|
if ($ele.hasClass('ignore-dirtyform')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.checked != element.defaultChecked) {
|
||||||
|
hasChangedObj = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if ($ele.is('input') || $ele.is('textarea')) {
|
||||||
|
if ($ele.hasClass('ignore-dirtyform')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.value != element.defaultValue) {
|
||||||
|
hasChangedObj = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if ($ele.is('select')) {
|
||||||
|
if ($ele.hasClass('ignore-dirtyform')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var option;
|
||||||
|
var defaultSelectedIndex = 0;
|
||||||
|
var numberOfOptions = element.options.length;
|
||||||
|
|
||||||
|
for (var i = 0; i < numberOfOptions; i++) {
|
||||||
|
option = element.options[i];
|
||||||
|
hasChangedObj = hasChangedObj || option.selected != option.defaultSelected;
|
||||||
|
if (option.defaultSelected) {
|
||||||
|
defaultSelectedIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasChangedObj && !element.multiple) {
|
||||||
|
hasChangedObj = defaultSelectedIndex != element.selectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasChangedObj) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return hasChangedObj;
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.extend({
|
||||||
|
dirtyForm: dirtyForm
|
||||||
|
});
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
$(document).on('submit', 'form', function() {
|
||||||
|
$.fn.qorSlideoutBeforeHide = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on('change', 'form', function() {
|
||||||
|
if ($(this).dirtyForm()) {
|
||||||
|
$.fn.qorSlideoutBeforeHide = true;
|
||||||
|
} else {
|
||||||
|
$.fn.qorSlideoutBeforeHide = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
302
app/views/qor/assets/javascripts/qor/qor-filter-time.js
Normal file
302
app/views/qor/assets/javascripts/qor/qor-filter-time.js
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let location = window.location,
|
||||||
|
$document = $(document),
|
||||||
|
NAMESPACE = 'qor.filter',
|
||||||
|
EVENT_FILTER_CHANGE = 'filterChanged.' + NAMESPACE,
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
CLASS_BOTTOMSHEETS = '.qor-bottomsheets',
|
||||||
|
CLASS_DATE_START = '.qor-filter__start',
|
||||||
|
CLASS_DATE_END = '.qor-filter__end',
|
||||||
|
CLASS_SEARCH_PARAM = '[data-search-param]',
|
||||||
|
CLASS_FILTER_SELECTOR = '.qor-filter__dropdown',
|
||||||
|
CLASS_FILTER_TOGGLE = '.qor-filter-toggle',
|
||||||
|
CLASS_IS_SELECTED = 'is-selected';
|
||||||
|
|
||||||
|
function QorFilterTime(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorFilterTime.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorFilterTime.prototype = {
|
||||||
|
constructor: QorFilterTime,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.bind();
|
||||||
|
let $element = this.$element,
|
||||||
|
lcoal_moment = window.moment();
|
||||||
|
|
||||||
|
this.$timeStart = $element.find(CLASS_DATE_START);
|
||||||
|
this.$timeEnd = $element.find(CLASS_DATE_END);
|
||||||
|
this.$searchParam = $element.find(CLASS_SEARCH_PARAM);
|
||||||
|
this.$searchButton = $element.find(this.options.button);
|
||||||
|
|
||||||
|
this.startWeekDate = lcoal_moment.startOf('isoweek').toDate();
|
||||||
|
this.endWeekDate = lcoal_moment.endOf('isoweek').toDate();
|
||||||
|
|
||||||
|
this.startMonthDate = lcoal_moment.startOf('month').toDate();
|
||||||
|
this.endMonthDate = lcoal_moment.endOf('month').toDate();
|
||||||
|
this.initActionTemplate();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
var options = this.options;
|
||||||
|
|
||||||
|
this.$element
|
||||||
|
.on(EVENT_CLICK, options.trigger, this.show.bind(this))
|
||||||
|
.on(EVENT_CLICK, options.label, this.setFilterTime.bind(this))
|
||||||
|
.on(EVENT_CLICK, options.clear, this.clear.bind(this))
|
||||||
|
.on(EVENT_CLICK, options.button, this.search.bind(this));
|
||||||
|
|
||||||
|
$document.on(EVENT_CLICK, this.close);
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element.off(EVENT_CLICK);
|
||||||
|
},
|
||||||
|
|
||||||
|
initActionTemplate: function() {
|
||||||
|
let paramFrom = this.$element.data('schedule-from');
|
||||||
|
let paramTo = this.$element.data('schedule-to');
|
||||||
|
|
||||||
|
|
||||||
|
let scheduleStartAt = this.getUrlParameter(paramFrom || 'schedule_start_at');
|
||||||
|
let scheduleEndAt = this.getUrlParameter(paramTo || 'schedule_end_at');
|
||||||
|
let $filterToggle = $(this.options.trigger);
|
||||||
|
|
||||||
|
if (scheduleStartAt || scheduleEndAt) {
|
||||||
|
this.$timeStart.val(scheduleStartAt);
|
||||||
|
this.$timeEnd.val(scheduleEndAt);
|
||||||
|
|
||||||
|
scheduleEndAt = !scheduleEndAt ? '' : ' - ' + scheduleEndAt;
|
||||||
|
$filterToggle
|
||||||
|
.addClass('active clearable')
|
||||||
|
.find('.qor-selector-label')
|
||||||
|
.html(scheduleStartAt + scheduleEndAt);
|
||||||
|
$filterToggle.append('<i class="material-icons qor-selector-clear">clear</i>');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function() {
|
||||||
|
this.$element.find(CLASS_FILTER_SELECTOR).toggle();
|
||||||
|
},
|
||||||
|
|
||||||
|
close: function(e) {
|
||||||
|
var $target = $(e.target),
|
||||||
|
$filter = $(CLASS_FILTER_SELECTOR),
|
||||||
|
filterVisible = $filter.is(':visible'),
|
||||||
|
isInFilter = $target.closest(CLASS_FILTER_SELECTOR).length,
|
||||||
|
isInToggle = $target.closest(CLASS_FILTER_TOGGLE).length,
|
||||||
|
isInModal = $target.closest('.qor-modal').length,
|
||||||
|
isInTimePicker = $target.closest('.ui-timepicker-wrapper').length;
|
||||||
|
|
||||||
|
if (filterVisible && (isInFilter || isInToggle || isInModal || isInTimePicker)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$filter.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
setFilterTime: function(e) {
|
||||||
|
let $target = $(e.target),
|
||||||
|
data = $target.data(),
|
||||||
|
range = data.filterRange,
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
startDate,
|
||||||
|
endDate;
|
||||||
|
|
||||||
|
if (!range) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(this.options.label).removeClass(CLASS_IS_SELECTED);
|
||||||
|
$target.addClass(CLASS_IS_SELECTED);
|
||||||
|
|
||||||
|
if (range == 'events') {
|
||||||
|
this.$timeStart.val(data.scheduleStartAt || '');
|
||||||
|
this.$timeEnd.val(data.scheduleEndAt || '');
|
||||||
|
this.$searchButton.click();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (range) {
|
||||||
|
case 'today':
|
||||||
|
startDate = endDate = new Date();
|
||||||
|
break;
|
||||||
|
case 'week':
|
||||||
|
startDate = this.startWeekDate;
|
||||||
|
endDate = this.endWeekDate;
|
||||||
|
break;
|
||||||
|
case 'month':
|
||||||
|
startDate = this.startMonthDate;
|
||||||
|
endDate = this.endMonthDate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!startDate || !endDate) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
startTime = this.getTime(startDate) + ' 00:00';
|
||||||
|
endTime = this.getTime(endDate) + ' 23:59';
|
||||||
|
|
||||||
|
this.$timeStart.val(startTime);
|
||||||
|
this.$timeEnd.val(endTime);
|
||||||
|
this.$searchButton.click();
|
||||||
|
},
|
||||||
|
|
||||||
|
getTime: function(dateNow) {
|
||||||
|
var month = dateNow.getMonth() + 1,
|
||||||
|
date = dateNow.getDate();
|
||||||
|
|
||||||
|
month = month < 10 ? '0' + month : month;
|
||||||
|
date = date < 10 ? '0' + date : date;
|
||||||
|
|
||||||
|
return dateNow.getFullYear() + '-' + month + '-' + date;
|
||||||
|
},
|
||||||
|
|
||||||
|
clear: function() {
|
||||||
|
var $trigger = $(this.options.trigger),
|
||||||
|
$label = $trigger.find('.qor-selector-label');
|
||||||
|
|
||||||
|
$trigger.removeClass('active clearable');
|
||||||
|
$label.html($label.data('label'));
|
||||||
|
this.$timeStart.val('');
|
||||||
|
this.$timeEnd.val('');
|
||||||
|
|
||||||
|
this.$searchButton.click();
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUrlParameter: function(name) {
|
||||||
|
let search = decodeURIComponent(location.search),
|
||||||
|
parameterName = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'),
|
||||||
|
regex = new RegExp('[\\?&]' + parameterName + '=([^&#]*)'),
|
||||||
|
results = regex.exec(search);
|
||||||
|
|
||||||
|
return results === null ? '' : results[1].replace(/\+/g, ' ');
|
||||||
|
},
|
||||||
|
|
||||||
|
updateQueryStringParameter: function(key, value, url) {
|
||||||
|
let href = url || location.href,
|
||||||
|
local_hash = href.match(/#\S*$/) || '',
|
||||||
|
escapedkey = String(key).replace(/[\\^$*+?.()|[\]{}]/g, '\\$&'),
|
||||||
|
re = new RegExp('([?&])' + escapedkey + '=.*?(&|$)', 'i'),
|
||||||
|
separator = href.indexOf('?') !== -1 ? '&' : '?';
|
||||||
|
|
||||||
|
if (local_hash) {
|
||||||
|
local_hash = local_hash[0];
|
||||||
|
href = href.replace(local_hash, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (href.match(re)) {
|
||||||
|
if (value) {
|
||||||
|
href = href.replace(re, '$1' + key + '=' + value + '$2');
|
||||||
|
} else {
|
||||||
|
if (RegExp.$1 === '?' || RegExp.$1 === RegExp.$2) {
|
||||||
|
href = href.replace(re, '$1');
|
||||||
|
} else {
|
||||||
|
href = href.replace(re, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (value) {
|
||||||
|
href = href + separator + key + '=' + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return href + local_hash;
|
||||||
|
},
|
||||||
|
|
||||||
|
search: function() {
|
||||||
|
var $searchParam = this.$searchParam,
|
||||||
|
href = location.href,
|
||||||
|
_this = this,
|
||||||
|
type = 'qor.filter.time';
|
||||||
|
|
||||||
|
if (!$searchParam.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$searchParam.each(function() {
|
||||||
|
var $this = $(this),
|
||||||
|
searchParam = $this.data().searchParam,
|
||||||
|
val = $this.val();
|
||||||
|
|
||||||
|
href = _this.updateQueryStringParameter(searchParam, val, href);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.$element.closest(CLASS_BOTTOMSHEETS).length) {
|
||||||
|
$(CLASS_BOTTOMSHEETS).trigger(EVENT_FILTER_CHANGE, [href, type]);
|
||||||
|
} else {
|
||||||
|
location.href = href;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorFilterTime.DEFAULTS = {
|
||||||
|
label: false,
|
||||||
|
trigger: false,
|
||||||
|
button: false,
|
||||||
|
clear: false
|
||||||
|
};
|
||||||
|
|
||||||
|
QorFilterTime.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorFilterTime(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = '[data-toggle="qor.filter.time"]';
|
||||||
|
var options = {
|
||||||
|
label: '.qor-filter__block-buttons button',
|
||||||
|
trigger: 'a.qor-filter-toggle',
|
||||||
|
button: '.qor-filter__button-search',
|
||||||
|
clear: '.qor-selector-clear'
|
||||||
|
};
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorFilterTime.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorFilterTime.plugin.call($(selector, e.target), options);
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorFilterTime;
|
||||||
|
});
|
||||||
237
app/views/qor/assets/javascripts/qor/qor-filter.js
Normal file
237
app/views/qor/assets/javascripts/qor/qor-filter.js
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let location = window.location,
|
||||||
|
NAMESPACE = 'qor.filter',
|
||||||
|
EVENT_FILTER_CHANGE = 'filterChanged.' + NAMESPACE,
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
EVENT_CHANGE = 'change.' + NAMESPACE,
|
||||||
|
CLASS_IS_ACTIVE = 'is-active',
|
||||||
|
CLASS_BOTTOMSHEETS = '.qor-bottomsheets';
|
||||||
|
|
||||||
|
function encodeSearch(data, detached) {
|
||||||
|
var search = decodeURI(location.search);
|
||||||
|
var per_page = location.search.match(/per_page=\d+/);
|
||||||
|
var params;
|
||||||
|
|
||||||
|
search = search.replace(/per_page=\d+/g,'').replace(/page=\d+/,'page=1');
|
||||||
|
|
||||||
|
|
||||||
|
if(per_page && per_page.length){
|
||||||
|
search = search + "&" + per_page[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($.isArray(data)) {
|
||||||
|
params = decodeSearch(search);
|
||||||
|
|
||||||
|
$.each(data, function(i, param) {
|
||||||
|
i = $.inArray(param, params);
|
||||||
|
|
||||||
|
if (i === -1) {
|
||||||
|
params.push(param);
|
||||||
|
} else if (detached) {
|
||||||
|
params.splice(i, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
search = '?' + params.join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
return search;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeSearch(search) {
|
||||||
|
var data = [];
|
||||||
|
|
||||||
|
if (search && search.indexOf('?') > -1) {
|
||||||
|
search = search.replace(/\+/g, ' ').split('?')[1];
|
||||||
|
|
||||||
|
if (search && search.indexOf('#') > -1) {
|
||||||
|
search = search.split('#')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (search) {
|
||||||
|
// search = search.toLowerCase();
|
||||||
|
data = $.map(search.split('&'), function(n) {
|
||||||
|
var param = [];
|
||||||
|
var value;
|
||||||
|
|
||||||
|
n = n.split('=');
|
||||||
|
value = n[1];
|
||||||
|
param.push(n[0]);
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
value = $.trim(decodeURIComponent(value));
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
param.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return param.join('=');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function QorFilter(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorFilter.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorFilter.prototype = {
|
||||||
|
constructor: QorFilter,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
// this.parse();
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
var options = this.options;
|
||||||
|
|
||||||
|
this.$element.on(EVENT_CLICK, options.label, $.proxy(this.toggle, this)).on(EVENT_CHANGE, options.group, $.proxy(this.toggle, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element.off(EVENT_CLICK, this.toggle).off(EVENT_CHANGE, this.toggle);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle: function(e) {
|
||||||
|
let $target = $(e.currentTarget),
|
||||||
|
data = [],
|
||||||
|
params,
|
||||||
|
param,
|
||||||
|
search,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
index,
|
||||||
|
matched,
|
||||||
|
paramName;
|
||||||
|
|
||||||
|
if ($target.is('select')) {
|
||||||
|
params = decodeSearch(decodeURI(location.search));
|
||||||
|
|
||||||
|
paramName = name = $target.attr('name');
|
||||||
|
value = $target.val();
|
||||||
|
param = [name];
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
param.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
param = param.join('=');
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
data.push(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
$target.children().each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var param = [name];
|
||||||
|
var value = $.trim($this.prop('value'));
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
param.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
param = param.join('=');
|
||||||
|
index = $.inArray(param, params);
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
matched = param;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
data.push(matched);
|
||||||
|
search = encodeSearch(data, true);
|
||||||
|
} else {
|
||||||
|
search = encodeSearch(data);
|
||||||
|
}
|
||||||
|
} else if ($target.is('a')) {
|
||||||
|
e.preventDefault();
|
||||||
|
paramName = $target.data().paramName;
|
||||||
|
data = decodeSearch($target.attr('href'));
|
||||||
|
if ($target.hasClass(CLASS_IS_ACTIVE)) {
|
||||||
|
search = encodeSearch(data, true); // set `true` to detach
|
||||||
|
} else {
|
||||||
|
search = encodeSearch(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.$element.closest(CLASS_BOTTOMSHEETS).length) {
|
||||||
|
$(CLASS_BOTTOMSHEETS).trigger(EVENT_FILTER_CHANGE, [search, paramName]);
|
||||||
|
} else {
|
||||||
|
location.search = search;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorFilter.DEFAULTS = {
|
||||||
|
label: false,
|
||||||
|
group: false
|
||||||
|
};
|
||||||
|
|
||||||
|
QorFilter.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorFilter(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = '[data-toggle="qor.filter"]';
|
||||||
|
var options = {
|
||||||
|
label: 'a',
|
||||||
|
group: 'select'
|
||||||
|
};
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorFilter.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorFilter.plugin.call($(selector, e.target), options);
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorFilter;
|
||||||
|
});
|
||||||
169
app/views/qor/assets/javascripts/qor/qor-fixer.js
Normal file
169
app/views/qor/assets/javascripts/qor/qor-fixer.js
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let $window = $(window),
|
||||||
|
NAMESPACE = 'qor.fixer',
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_RESIZE = 'resize.' + NAMESPACE,
|
||||||
|
EVENT_SCROLL = 'scroll.' + NAMESPACE,
|
||||||
|
CLASS_FIXED_TABLE = 'qor-table-fixed-header',
|
||||||
|
CLASS_HEADER = '.qor-page__header';
|
||||||
|
|
||||||
|
function QorFixer(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorFixer.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorFixer.prototype = {
|
||||||
|
constructor: QorFixer,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
var options = this.options;
|
||||||
|
var $this = this.$element;
|
||||||
|
if (this.isNeedBuild()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$thead = $this.find('> thead');
|
||||||
|
this.$tbody = $this.find('> tbody');
|
||||||
|
|
||||||
|
this.$header = $(options.header);
|
||||||
|
this.$subHeader = $(options.subHeader);
|
||||||
|
this.$content = $(options.content);
|
||||||
|
this.marginBottomPX = parseInt(this.$subHeader.css('marginBottom'));
|
||||||
|
this.paddingHeight = options.paddingHeight;
|
||||||
|
|
||||||
|
this.resize();
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$content.on(EVENT_SCROLL, this.toggle.bind(this));
|
||||||
|
$window.on(EVENT_RESIZE, this.resize.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$content.off(EVENT_SCROLL, this.toggle).off(EVENT_RESIZE, this.resize);
|
||||||
|
},
|
||||||
|
|
||||||
|
isNeedBuild: function() {
|
||||||
|
var $this = this.$element;
|
||||||
|
// disable fixer if have multiple tables or in search page or in media library list page
|
||||||
|
if (
|
||||||
|
$('.qor-page__body .qor-js-table').length > 1 ||
|
||||||
|
$('.qor-global-search--container').length > 0 ||
|
||||||
|
$this.hasClass('qor-table--medialibrary') ||
|
||||||
|
$this.is(':hidden') ||
|
||||||
|
$this.find('tbody > tr:visible').length <= 1 ||
|
||||||
|
$this.data("disable-fixer")
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
build: function() {
|
||||||
|
let headerWidth = [],
|
||||||
|
$items = this.$tbody.find('> tr:first').children();
|
||||||
|
|
||||||
|
$items.each(function() {
|
||||||
|
let tdWidth = $(this).outerWidth();
|
||||||
|
$(this).outerWidth(tdWidth);
|
||||||
|
headerWidth.push(tdWidth);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$thead
|
||||||
|
.find('>tr')
|
||||||
|
.children()
|
||||||
|
.each(function(i) {
|
||||||
|
$(this).outerWidth(headerWidth[i]);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle: function() {
|
||||||
|
if (!this.$content.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let $element = this.$element,
|
||||||
|
$thead = this.$thead,
|
||||||
|
scrollTop = this.$content.scrollTop(),
|
||||||
|
offsetTop = this.$subHeader.outerHeight() + this.paddingHeight + this.marginBottomPX,
|
||||||
|
headerHeight = $('.qor-page__header').outerHeight(),
|
||||||
|
pageTop = this.$content.offset().top + $(CLASS_HEADER).height();
|
||||||
|
|
||||||
|
if (scrollTop > offsetTop - headerHeight) {
|
||||||
|
$thead.css({top: pageTop});
|
||||||
|
$element.addClass(CLASS_FIXED_TABLE);
|
||||||
|
} else {
|
||||||
|
$element.removeClass(CLASS_FIXED_TABLE);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resize: function() {
|
||||||
|
this.build();
|
||||||
|
this.toggle();
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
if (this.buildCheck()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorFixer.DEFAULTS = {
|
||||||
|
header: false,
|
||||||
|
content: false
|
||||||
|
};
|
||||||
|
|
||||||
|
QorFixer.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
$this.data(NAMESPACE, (data = new QorFixer(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.call(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = '.qor-js-table';
|
||||||
|
var options = {
|
||||||
|
header: '.mdl-layout__header',
|
||||||
|
subHeader: '.qor-page__header',
|
||||||
|
content: '.mdl-layout__content',
|
||||||
|
paddingHeight: 2 // Fix sub header height bug
|
||||||
|
};
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorFixer.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorFixer.plugin.call($(selector, e.target), options);
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorFixer;
|
||||||
|
});
|
||||||
202
app/views/qor/assets/javascripts/qor/qor-inline-edit.js
Normal file
202
app/views/qor/assets/javascripts/qor/qor-inline-edit.js
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const NAMESPACE = 'qor.inlineEdit',
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
EVENT_MOUSEENTER = 'mouseenter.' + NAMESPACE,
|
||||||
|
EVENT_MOUSELEAVE = 'mouseleave.' + NAMESPACE,
|
||||||
|
CLASS_FIELD = '.qor-field',
|
||||||
|
CLASS_FIELD_SHOW = '.qor-field__show',
|
||||||
|
CLASS_FIELD_SHOW_INNER = '.qor-field__show-inner',
|
||||||
|
CLASS_EDIT = '.qor-inlineedit__edit',
|
||||||
|
CLASS_SAVE = '.qor-inlineedit__save',
|
||||||
|
CLASS_BUTTONS = '.qor-inlineedit__buttons',
|
||||||
|
CLASS_CANCEL = '.qor-inlineedit__cancel',
|
||||||
|
CLASS_CONTAINER = 'qor-inlineedit__field';
|
||||||
|
|
||||||
|
function QorInlineEdit(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorInlineEdit.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getJsonData(names, data) {
|
||||||
|
let key,
|
||||||
|
value = data[names[0].slice(1)];
|
||||||
|
|
||||||
|
if (names.length > 1) {
|
||||||
|
for (let i = 1; i < names.length; i++) {
|
||||||
|
key = names[i].slice(1);
|
||||||
|
value = $.isArray(value) ? value[0][key] : value[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
QorInlineEdit.prototype = {
|
||||||
|
constructor: QorInlineEdit,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
let $element = this.$element,
|
||||||
|
saveButton = $element.data('button-save'),
|
||||||
|
cancelButton = $element.data('button-cancel');
|
||||||
|
|
||||||
|
this.TEMPLATE_SAVE = `<div class="qor-inlineedit__buttons">
|
||||||
|
<button class="mdl-button mdl-button--colored mdl-js-button qor-button--small qor-inlineedit__cancel" type="button">${cancelButton}</button>
|
||||||
|
<button class="mdl-button mdl-button--colored mdl-js-button qor-button--small qor-inlineedit__save" type="button">${saveButton}</button>
|
||||||
|
</div>`;
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$element
|
||||||
|
.on(EVENT_MOUSEENTER, CLASS_FIELD_SHOW, this.showEditButton)
|
||||||
|
.on(EVENT_MOUSELEAVE, CLASS_FIELD_SHOW, this.hideEditButton)
|
||||||
|
.on(EVENT_CLICK, CLASS_CANCEL, this.hideEdit)
|
||||||
|
.on(EVENT_CLICK, CLASS_SAVE, this.saveEdit)
|
||||||
|
.on(EVENT_CLICK, CLASS_EDIT, this.showEdit.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element
|
||||||
|
.off(EVENT_MOUSEENTER)
|
||||||
|
.off(EVENT_MOUSELEAVE)
|
||||||
|
.off(EVENT_CLICK);
|
||||||
|
},
|
||||||
|
|
||||||
|
showEditButton: function(e) {
|
||||||
|
let $edit = $(QorInlineEdit.TEMPLATE_EDIT),
|
||||||
|
$field = $(e.target).closest(CLASS_FIELD);
|
||||||
|
|
||||||
|
if ($field.find('input:disabled, textarea:disabled,select:disabled').length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$edit.appendTo($(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
hideEditButton: function() {
|
||||||
|
$('.qor-inlineedit__edit').remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
showEdit: function(e) {
|
||||||
|
let $parent = $(e.target)
|
||||||
|
.closest(CLASS_EDIT)
|
||||||
|
.hide()
|
||||||
|
.closest(CLASS_FIELD)
|
||||||
|
.addClass(CLASS_CONTAINER),
|
||||||
|
$save = $(this.TEMPLATE_SAVE);
|
||||||
|
|
||||||
|
$save.appendTo($parent);
|
||||||
|
},
|
||||||
|
|
||||||
|
hideEdit: function() {
|
||||||
|
let $parent = $(this)
|
||||||
|
.closest(CLASS_FIELD)
|
||||||
|
.removeClass(CLASS_CONTAINER);
|
||||||
|
$parent.find(CLASS_BUTTONS).remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
saveEdit: function() {
|
||||||
|
let $btn = $(this),
|
||||||
|
$parent = $btn.closest(CLASS_FIELD),
|
||||||
|
$form = $btn.closest('form'),
|
||||||
|
$hiddenInput = $parent.closest('.qor-fieldset').find('input.qor-hidden__primary_key[type="hidden"]'),
|
||||||
|
$input = $parent.find('input[name*="QorResource"],textarea[name*="QorResource"],select[name*="QorResource"]'),
|
||||||
|
names = $input.length && $input.prop('name').match(/\.\w+/g),
|
||||||
|
inputData = $input.serialize();
|
||||||
|
|
||||||
|
if ($hiddenInput.length) {
|
||||||
|
inputData = `${inputData}&${$hiddenInput.serialize()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (names.length) {
|
||||||
|
$.ajax($form.prop('action'), {
|
||||||
|
method: $form.prop('method'),
|
||||||
|
data: inputData,
|
||||||
|
dataType: 'json',
|
||||||
|
beforeSend: function() {
|
||||||
|
$btn.prop('disabled', true);
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
let newValue = getJsonData(names, data),
|
||||||
|
$show = $parent.removeClass(CLASS_CONTAINER).find(CLASS_FIELD_SHOW),
|
||||||
|
$inner = $show.find(CLASS_FIELD_SHOW_INNER);
|
||||||
|
|
||||||
|
if (typeof newValue === 'string' || newValue instanceof String){
|
||||||
|
newValue = newValue.escapeSymbol();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($inner.length) {
|
||||||
|
$inner.html(newValue);
|
||||||
|
} else {
|
||||||
|
$show.html(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent.find(CLASS_BUTTONS).remove();
|
||||||
|
$btn.prop('disabled', false);
|
||||||
|
},
|
||||||
|
error: function(err) {
|
||||||
|
window.QOR.handleAjaxError(err);
|
||||||
|
$btn.prop('disabled', false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorInlineEdit.DEFAULTS = {};
|
||||||
|
|
||||||
|
QorInlineEdit.TEMPLATE_EDIT = `<button class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored qor-inlineedit__edit" type="button"><i class="material-icons">mode_edit</i></button>`;
|
||||||
|
|
||||||
|
QorInlineEdit.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
$this.data(NAMESPACE, (data = new QorInlineEdit(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.call(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
let selector = '[data-toggle="qor.inlineEdit"]',
|
||||||
|
options = {};
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorInlineEdit.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorInlineEdit.plugin.call($(selector, e.target), options);
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorInlineEdit;
|
||||||
|
});
|
||||||
59
app/views/qor/assets/javascripts/qor/qor-material.js
Normal file
59
app/views/qor/assets/javascripts/qor/qor-material.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let componentHandler = window.componentHandler,
|
||||||
|
NAMESPACE = 'qor.material',
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_UPDATE = 'update.' + NAMESPACE,
|
||||||
|
SELECTOR_COMPONENT = '[class*="mdl-js"],[class*="mdl-tooltip"]';
|
||||||
|
|
||||||
|
function enable(target) {
|
||||||
|
/*jshint undef:false */
|
||||||
|
if (componentHandler) {
|
||||||
|
// Enable all MDL (Material Design Lite) components within the target element
|
||||||
|
if ($(target).is(SELECTOR_COMPONENT)) {
|
||||||
|
componentHandler.upgradeElements(target);
|
||||||
|
} else {
|
||||||
|
componentHandler.upgradeElements($(SELECTOR_COMPONENT, target).toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function disable(target) {
|
||||||
|
/*jshint undef:false */
|
||||||
|
if (componentHandler) {
|
||||||
|
// Destroy all MDL (Material Design Lite) components within the target element
|
||||||
|
if ($(target).is(SELECTOR_COMPONENT)) {
|
||||||
|
componentHandler.downgradeElements(target);
|
||||||
|
} else {
|
||||||
|
componentHandler.downgradeElements($(SELECTOR_COMPONENT, target).toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
enable(e.target);
|
||||||
|
})
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
disable(e.target);
|
||||||
|
})
|
||||||
|
.on(EVENT_UPDATE, function(e) {
|
||||||
|
disable(e.target);
|
||||||
|
enable(e.target);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
235
app/views/qor/assets/javascripts/qor/qor-modal.js
Normal file
235
app/views/qor/assets/javascripts/qor/qor-modal.js
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let $document = $(document),
|
||||||
|
NAMESPACE = 'qor.modal',
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
EVENT_KEYUP = 'keyup.' + NAMESPACE,
|
||||||
|
EVENT_SHOW = 'show.' + NAMESPACE,
|
||||||
|
EVENT_SHOWN = 'shown.' + NAMESPACE,
|
||||||
|
EVENT_HIDE = 'hide.' + NAMESPACE,
|
||||||
|
EVENT_HIDDEN = 'hidden.' + NAMESPACE,
|
||||||
|
EVENT_TRANSITION_END = 'transitionend',
|
||||||
|
CLASS_OPEN = 'qor-modal-open',
|
||||||
|
CLASS_SHOWN = 'shown',
|
||||||
|
CLASS_FADE = 'fade',
|
||||||
|
CLASS_IN = 'in',
|
||||||
|
ARIA_HIDDEN = 'aria-hidden';
|
||||||
|
|
||||||
|
function QorModal(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorModal.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.transitioning = false;
|
||||||
|
this.fadable = false;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorModal.prototype = {
|
||||||
|
constructor: QorModal,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.fadable = this.$element.hasClass(CLASS_FADE);
|
||||||
|
|
||||||
|
if (this.options.show) {
|
||||||
|
this.show();
|
||||||
|
} else {
|
||||||
|
this.toggle();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$element.on(EVENT_CLICK, $.proxy(this.click, this));
|
||||||
|
|
||||||
|
if (this.options.keyboard) {
|
||||||
|
$document.on(EVENT_KEYUP, $.proxy(this.keyup, this));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element.off(EVENT_CLICK, this.click);
|
||||||
|
|
||||||
|
if (this.options.keyboard) {
|
||||||
|
$document.off(EVENT_KEYUP, this.keyup);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
click: function(e) {
|
||||||
|
var element = this.$element[0];
|
||||||
|
var target = e.target;
|
||||||
|
|
||||||
|
if (target === element && this.options.backdrop) {
|
||||||
|
this.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (target !== element) {
|
||||||
|
if ($(target).data('dismiss') === 'modal') {
|
||||||
|
this.hide();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
target = target.parentNode;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
keyup: function(e) {
|
||||||
|
if (e.which === 27) {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function(noTransition) {
|
||||||
|
var $this = this.$element,
|
||||||
|
showEvent;
|
||||||
|
|
||||||
|
if (this.transitioning || $this.hasClass(CLASS_IN)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showEvent = $.Event(EVENT_SHOW);
|
||||||
|
$this.trigger(showEvent);
|
||||||
|
|
||||||
|
if (showEvent.isDefaultPrevented()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$document.find('body').addClass(CLASS_OPEN);
|
||||||
|
|
||||||
|
/*jshint expr:true */
|
||||||
|
$this
|
||||||
|
.addClass(CLASS_SHOWN)
|
||||||
|
.scrollTop(0)
|
||||||
|
.get(0).offsetHeight; // reflow for transition
|
||||||
|
this.transitioning = true;
|
||||||
|
|
||||||
|
if (noTransition || !this.fadable) {
|
||||||
|
$this.addClass(CLASS_IN);
|
||||||
|
this.shown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.one(EVENT_TRANSITION_END, $.proxy(this.shown, this));
|
||||||
|
$this.addClass(CLASS_IN);
|
||||||
|
},
|
||||||
|
|
||||||
|
shown: function() {
|
||||||
|
this.transitioning = false;
|
||||||
|
this.bind();
|
||||||
|
this.$element
|
||||||
|
.attr(ARIA_HIDDEN, false)
|
||||||
|
.trigger(EVENT_SHOWN)
|
||||||
|
.focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function(noTransition) {
|
||||||
|
var $this = this.$element,
|
||||||
|
hideEvent;
|
||||||
|
|
||||||
|
if (this.transitioning || !$this.hasClass(CLASS_IN)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideEvent = $.Event(EVENT_HIDE);
|
||||||
|
$this.trigger(hideEvent);
|
||||||
|
|
||||||
|
if (hideEvent.isDefaultPrevented()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$document.find('body').removeClass(CLASS_OPEN);
|
||||||
|
this.transitioning = true;
|
||||||
|
|
||||||
|
if (noTransition || !this.fadable) {
|
||||||
|
$this.removeClass(CLASS_IN);
|
||||||
|
this.hidden();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.one(EVENT_TRANSITION_END, $.proxy(this.hidden, this));
|
||||||
|
$this.removeClass(CLASS_IN);
|
||||||
|
},
|
||||||
|
|
||||||
|
hidden: function() {
|
||||||
|
this.transitioning = false;
|
||||||
|
this.unbind();
|
||||||
|
this.$element
|
||||||
|
.removeClass(CLASS_SHOWN)
|
||||||
|
.attr(ARIA_HIDDEN, true)
|
||||||
|
.trigger(EVENT_HIDDEN);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle: function() {
|
||||||
|
if (this.$element.hasClass(CLASS_IN)) {
|
||||||
|
this.hide();
|
||||||
|
} else {
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorModal.DEFAULTS = {
|
||||||
|
backdrop: false,
|
||||||
|
keyboard: true,
|
||||||
|
show: true
|
||||||
|
};
|
||||||
|
|
||||||
|
QorModal.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorModal(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.qorModal = QorModal.plugin;
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = '.qor-modal';
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_CLICK, '[data-toggle="qor.modal"]', function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data();
|
||||||
|
var $target = $(data.target || $this.attr('href'));
|
||||||
|
|
||||||
|
QorModal.plugin.call($target, $target.data(NAMESPACE) ? 'toggle' : data);
|
||||||
|
})
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorModal.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorModal.plugin.call($(selector, e.target));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorModal;
|
||||||
|
});
|
||||||
109
app/views/qor/assets/javascripts/qor/qor-radio-tabs.js
Normal file
109
app/views/qor/assets/javascripts/qor/qor-radio-tabs.js
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
(function (factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function ($) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var NAMESPACE = 'qor.tabbar.radio';
|
||||||
|
var EVENT_ENABLE = 'enable.' + NAMESPACE;
|
||||||
|
var EVENT_DISABLE = 'disable.' + NAMESPACE;
|
||||||
|
var EVENT_CLICK = 'click.' + NAMESPACE;
|
||||||
|
var EVENT_SWITCHED = 'switched.' + NAMESPACE;
|
||||||
|
var CLASS_TAB = '[data-tab-target]';
|
||||||
|
var CLASS_TAB_SOURCE = '[data-tab-source]';
|
||||||
|
var CLASS_ACTIVE = 'is-active';
|
||||||
|
|
||||||
|
function QorTabRadio(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorTabRadio.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorTabRadio.prototype = {
|
||||||
|
constructor: QorTabRadio,
|
||||||
|
|
||||||
|
init: function () {
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function () {
|
||||||
|
this.$element.on(EVENT_CLICK, CLASS_TAB, this.switchTab.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function () {
|
||||||
|
this.$element.off(EVENT_CLICK, CLASS_TAB, this.switchTab);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
switchTab: function (e) {
|
||||||
|
var $target = $(e.target),
|
||||||
|
$element = this.$element,
|
||||||
|
$tabs = $element.find(CLASS_TAB),
|
||||||
|
$tabSources = $element.find(CLASS_TAB_SOURCE),
|
||||||
|
data = $target.data(),
|
||||||
|
tabTarget = data.tabTarget;
|
||||||
|
|
||||||
|
if ($target.hasClass(CLASS_ACTIVE)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tabs.removeClass(CLASS_ACTIVE);
|
||||||
|
$target.addClass(CLASS_ACTIVE);
|
||||||
|
|
||||||
|
$tabSources.hide().filter('[data-tab-source="' + tabTarget + '"]').show();
|
||||||
|
$element.trigger(EVENT_SWITCHED, [$element, tabTarget]);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
this.unbind();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorTabRadio.DEFAULTS = {};
|
||||||
|
|
||||||
|
QorTabRadio.plugin = function (options) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorTabRadio(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction(fn = data[options])) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
var selector = '[data-toggle="qor.tab.radio"]';
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function (e) {
|
||||||
|
QorTabRadio.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function (e) {
|
||||||
|
QorTabRadio.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorTabRadio;
|
||||||
|
|
||||||
|
});
|
||||||
452
app/views/qor/assets/javascripts/qor/qor-redactor.js
Normal file
452
app/views/qor/assets/javascripts/qor/qor-redactor.js
Normal file
@@ -0,0 +1,452 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === "function" && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(["jquery"], factory);
|
||||||
|
} else if (typeof exports === "object") {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require("jquery"));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let NAMESPACE = "qor.redactor",
|
||||||
|
EVENT_ENABLE = "enable." + NAMESPACE,
|
||||||
|
EVENT_DISABLE = "disable." + NAMESPACE,
|
||||||
|
EVENT_CLICK = "click." + NAMESPACE,
|
||||||
|
EVENT_ADD_CROP = "addCrop." + NAMESPACE,
|
||||||
|
EVENT_REMOVE_CROP = "removeCrop." + NAMESPACE,
|
||||||
|
EVENT_SHOWN = "shown.qor.modal",
|
||||||
|
EVENT_HIDDEN = "hidden.qor.modal",
|
||||||
|
EVENT_SCROLL = "scroll." + NAMESPACE,
|
||||||
|
CLASS_WRAPPER = ".qor-cropper__wrapper",
|
||||||
|
CLASS_SAVE = ".qor-cropper__save",
|
||||||
|
CLASS_CROPPER_TOGGLE = ".qor-cropper__toggle--redactor";
|
||||||
|
|
||||||
|
function encodeCropData(data) {
|
||||||
|
var nums = [];
|
||||||
|
|
||||||
|
if ($.isPlainObject(data)) {
|
||||||
|
$.each(data, function() {
|
||||||
|
nums.push(arguments[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return nums.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeCropData(data) {
|
||||||
|
var nums = data && data.split(",");
|
||||||
|
|
||||||
|
data = null;
|
||||||
|
|
||||||
|
if (nums && nums.length === 4) {
|
||||||
|
data = {
|
||||||
|
x: Number(nums[0]),
|
||||||
|
y: Number(nums[1]),
|
||||||
|
width: Number(nums[2]),
|
||||||
|
height: Number(nums[3])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function capitalize(str) {
|
||||||
|
if (typeof str === "string") {
|
||||||
|
str = str.charAt(0).toUpperCase() + str.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCapitalizeKeyObject(obj) {
|
||||||
|
var newObj = {},
|
||||||
|
key;
|
||||||
|
|
||||||
|
if ($.isPlainObject(obj)) {
|
||||||
|
for (key in obj) {
|
||||||
|
if (obj.hasOwnProperty(key)) {
|
||||||
|
newObj[capitalize(key)] = obj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceText(str, data) {
|
||||||
|
if (typeof str === "string") {
|
||||||
|
if (typeof data === "object") {
|
||||||
|
$.each(data, function(key, val) {
|
||||||
|
str = str.replace("$[" + String(key).toLowerCase() + "]", val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function redactorToolbarSrcoll($toolbar, $container, toolbarFixedTopOffset) {
|
||||||
|
let offsetTop = $container.offset().top,
|
||||||
|
containerHeight = $container.outerHeight(),
|
||||||
|
normallCSS = {
|
||||||
|
position: "relative",
|
||||||
|
top: "auto",
|
||||||
|
width: "auto"
|
||||||
|
},
|
||||||
|
fixedCSS = {
|
||||||
|
position: "fixed",
|
||||||
|
top: toolbarFixedTopOffset,
|
||||||
|
width: $container.width(),
|
||||||
|
boxShadow: "none"
|
||||||
|
};
|
||||||
|
if (offsetTop < toolbarFixedTopOffset) {
|
||||||
|
if (
|
||||||
|
Math.abs(offsetTop) < Math.abs(containerHeight - toolbarFixedTopOffset)
|
||||||
|
) {
|
||||||
|
$toolbar.css(fixedCSS);
|
||||||
|
$container.css("padding-top", $toolbar.outerHeight());
|
||||||
|
} else {
|
||||||
|
$toolbar.css(normallCSS);
|
||||||
|
$container.css("padding-top", 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$toolbar.css(normallCSS);
|
||||||
|
$container.css("padding-top", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function QorRedactor(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend(
|
||||||
|
true,
|
||||||
|
{},
|
||||||
|
QorRedactor.DEFAULTS,
|
||||||
|
$.isPlainObject(options) && options
|
||||||
|
);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorRedactor.prototype = {
|
||||||
|
constructor: QorRedactor,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
var options = this.options;
|
||||||
|
var $this = this.$element;
|
||||||
|
var $parent = $this.closest(options.parent);
|
||||||
|
|
||||||
|
if (!$parent.length) {
|
||||||
|
$parent = $this.parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$parent = $parent;
|
||||||
|
this.$button = $(QorRedactor.BUTTON);
|
||||||
|
this.$modal = $(replaceText(QorRedactor.MODAL, options.text)).appendTo(
|
||||||
|
"body"
|
||||||
|
);
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$element
|
||||||
|
.on(EVENT_ADD_CROP, $.proxy(this.addButton, this))
|
||||||
|
.on(EVENT_REMOVE_CROP, $.proxy(this.removeButton, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element
|
||||||
|
.off(EVENT_ADD_CROP)
|
||||||
|
.off(EVENT_REMOVE_CROP)
|
||||||
|
.off(EVENT_SCROLL);
|
||||||
|
},
|
||||||
|
|
||||||
|
addButton: function(e, image) {
|
||||||
|
var $image = $(image);
|
||||||
|
|
||||||
|
this.$button
|
||||||
|
.css("left", $(image).width() / 2)
|
||||||
|
.prependTo($image.parent())
|
||||||
|
.find(CLASS_CROPPER_TOGGLE)
|
||||||
|
.one(EVENT_CLICK, $.proxy(this.crop, this, $image));
|
||||||
|
},
|
||||||
|
|
||||||
|
removeButton: function() {
|
||||||
|
this.$button.find(CLASS_CROPPER_TOGGLE).off(EVENT_CLICK);
|
||||||
|
this.$button.detach();
|
||||||
|
},
|
||||||
|
|
||||||
|
crop: function($image) {
|
||||||
|
let options = this.options,
|
||||||
|
url = $image.attr("src"),
|
||||||
|
originalUrl = url,
|
||||||
|
$clone,
|
||||||
|
$modal = this.$modal;
|
||||||
|
|
||||||
|
if ($.isFunction(options.replace)) {
|
||||||
|
originalUrl = options.replace(originalUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
$clone = $(`<img src='${originalUrl}'>`);
|
||||||
|
|
||||||
|
$modal
|
||||||
|
.one(EVENT_SHOWN, function() {
|
||||||
|
$clone.cropper({
|
||||||
|
data: decodeCropData($image.attr("data-crop-options")),
|
||||||
|
background: false,
|
||||||
|
movable: false,
|
||||||
|
zoomable: false,
|
||||||
|
scalable: false,
|
||||||
|
rotatable: false,
|
||||||
|
checkImageOrigin: false,
|
||||||
|
|
||||||
|
ready: function() {
|
||||||
|
$modal.find(CLASS_SAVE).one(EVENT_CLICK, function() {
|
||||||
|
var cropData = $clone.cropper("getData", true);
|
||||||
|
|
||||||
|
$.ajax(options.remote, {
|
||||||
|
type: "POST",
|
||||||
|
contentType: "application/json",
|
||||||
|
data: JSON.stringify({
|
||||||
|
Url: url,
|
||||||
|
CropOptions: {
|
||||||
|
original: getCapitalizeKeyObject(cropData)
|
||||||
|
},
|
||||||
|
Crop: true
|
||||||
|
}),
|
||||||
|
dataType: "json",
|
||||||
|
|
||||||
|
success: function(response) {
|
||||||
|
if ($.isPlainObject(response) && response.url) {
|
||||||
|
$image
|
||||||
|
.attr("src", response.url)
|
||||||
|
.attr("data-crop-options", encodeCropData(cropData))
|
||||||
|
.removeAttr("style")
|
||||||
|
.removeAttr("rel");
|
||||||
|
|
||||||
|
if ($.isFunction(options.complete)) {
|
||||||
|
options.complete();
|
||||||
|
}
|
||||||
|
$modal.qorModal("hide");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.one(EVENT_HIDDEN, function() {
|
||||||
|
$clone.cropper("destroy").remove();
|
||||||
|
})
|
||||||
|
.qorModal("show")
|
||||||
|
.find(CLASS_WRAPPER)
|
||||||
|
.append($clone);
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$modal.qorModal("hide").remove();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorRedactor.DEFAULTS = {
|
||||||
|
remote: false,
|
||||||
|
parent: false,
|
||||||
|
toggle: false,
|
||||||
|
replace: null,
|
||||||
|
complete: null,
|
||||||
|
text: {
|
||||||
|
title: "Crop the image",
|
||||||
|
ok: "OK",
|
||||||
|
cancel: "Cancel"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorRedactor.BUTTON = `<div class="qor-redactor__image--buttons">
|
||||||
|
<span class="qor-redactor__image--edit" contenteditable="false">Edit</span>
|
||||||
|
<span class="qor-cropper__toggle--redactor" contenteditable="false">Crop</span>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorRedactor.MODAL = `<div class="qor-modal fade" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div class="mdl-card mdl-shadow--2dp" role="document">
|
||||||
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">$[title]</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting-text">
|
||||||
|
<div class="qor-cropper__wrapper"></div>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__actions mdl-card--border">
|
||||||
|
<a class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect qor-cropper__save">$[ok]</a>
|
||||||
|
<a class="mdl-button mdl-button--colored mdl-js-button mdl-js-ripple-effect" data-dismiss="modal">$[cancel]</a>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__menu">
|
||||||
|
<button class="mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-effect" data-dismiss="modal" aria-label="close">
|
||||||
|
<i class="material-icons">close</i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorRedactor.plugin = function(option) {
|
||||||
|
return this.each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
data = $this.data(NAMESPACE),
|
||||||
|
config,
|
||||||
|
fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (!window.$R) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/destroy/.test(option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = {}));
|
||||||
|
|
||||||
|
let editorButtons = [
|
||||||
|
"html",
|
||||||
|
"format",
|
||||||
|
"bold",
|
||||||
|
"italic",
|
||||||
|
"deleted",
|
||||||
|
"lists",
|
||||||
|
"image",
|
||||||
|
"file",
|
||||||
|
"link"
|
||||||
|
];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
imageUpload: $this.data("uploadUrl"),
|
||||||
|
fileUpload: $this.data("uploadUrl"),
|
||||||
|
buttons: editorButtons,
|
||||||
|
linkNewTab: true,
|
||||||
|
linkTitle: false,
|
||||||
|
autoparsePaste: false,
|
||||||
|
autoparseLinks: false,
|
||||||
|
multipleUpload: false,
|
||||||
|
toolbarFixedTarget:
|
||||||
|
!$this.closest(".qor-slideout").length &&
|
||||||
|
!$this.closest(".qor-bottomsheets").length
|
||||||
|
? $("main.mdl-layout__content").length
|
||||||
|
? "main.mdl-layout__content"
|
||||||
|
: document
|
||||||
|
: document,
|
||||||
|
|
||||||
|
callbacks: {
|
||||||
|
started: function() {
|
||||||
|
let $container = $(this.container.$container.nodes[0]),
|
||||||
|
$toolbar = $(this.toolbar.$toolbar.nodes[0]),
|
||||||
|
isInSlideout = $(".qor-slideout").is(":visible"),
|
||||||
|
toolbarFixedTarget,
|
||||||
|
toolbarFixedTopOffset = 64;
|
||||||
|
|
||||||
|
if (isInSlideout) {
|
||||||
|
if ($this.closest(".qor-bottomsheets").length != 0) {
|
||||||
|
toolbarFixedTarget = $this.closest(".qor-page__body");
|
||||||
|
toolbarFixedTopOffset = $this
|
||||||
|
.closest(".qor-page__body")
|
||||||
|
.offset().top;
|
||||||
|
} else {
|
||||||
|
toolbarFixedTarget = ".qor-slideout__body";
|
||||||
|
toolbarFixedTopOffset = $(".qor-slideout__header").height();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toolbarFixedTarget = ".qor-layout main.qor-page";
|
||||||
|
toolbarFixedTopOffset =
|
||||||
|
toolbarFixedTopOffset +
|
||||||
|
$(toolbarFixedTarget)
|
||||||
|
.find(".qor-page__header")
|
||||||
|
.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
$(toolbarFixedTarget).on(EVENT_SCROLL, function() {
|
||||||
|
redactorToolbarSrcoll(
|
||||||
|
$toolbar,
|
||||||
|
$container,
|
||||||
|
toolbarFixedTopOffset
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!$this.data("cropUrl")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(
|
||||||
|
NAMESPACE,
|
||||||
|
(data = new QorRedactor($this, {
|
||||||
|
remote: $this.data("cropUrl"),
|
||||||
|
text: $this.data("text"),
|
||||||
|
parent: ".qor-field",
|
||||||
|
toggle: ".qor-cropper__toggle--redactor",
|
||||||
|
replace: function(url) {
|
||||||
|
return url.replace(/\.\w+$/, function(extension) {
|
||||||
|
return ".original" + extension;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
complete: $.proxy(function() {
|
||||||
|
this.code.sync();
|
||||||
|
}, this)
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
imageUpload: function(image, json) {
|
||||||
|
var $image = $(image);
|
||||||
|
json.filelink && $image.prop("src", json.filelink);
|
||||||
|
},
|
||||||
|
|
||||||
|
insertedLink: function(link) {
|
||||||
|
var $link = $(link),
|
||||||
|
description = this.link.description;
|
||||||
|
|
||||||
|
$link.prop("title", description ? description : $link.text());
|
||||||
|
this.link.description = "";
|
||||||
|
this.link.linkUrlText = "";
|
||||||
|
this.link.insertedTriggered = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
fileUpload: function(link, json) {
|
||||||
|
$(link)
|
||||||
|
.prop("href", json.filelink)
|
||||||
|
.html(json.filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.extend(config, $this.data("redactorSettings"));
|
||||||
|
window.$R.prototype.constructor.services.editor.prototype.focus = function() {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
window.$R(this, config);
|
||||||
|
} else {
|
||||||
|
if (/destroy/.test(option)) {
|
||||||
|
window.$R(this, "destroy");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof option === "string" && $.isFunction((fn = data[option]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = 'textarea[data-toggle="qor.redactor"]';
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorRedactor.plugin.call($(selector, e.target), "destroy");
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorRedactor.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorRedactor;
|
||||||
|
});
|
||||||
417
app/views/qor/assets/javascripts/qor/qor-replicator.js
Normal file
417
app/views/qor/assets/javascripts/qor/qor-replicator.js
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let _ = window._,
|
||||||
|
QOR = window.QOR,
|
||||||
|
NAMESPACE = 'qor.replicator',
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_SUBMIT = 'submit.' + NAMESPACE,
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
EVENT_SLIDEOUTBEFORESEND = 'slideoutBeforeSend.qor.slideout.replicator',
|
||||||
|
EVENT_SELECTCOREBEFORESEND = 'selectcoreBeforeSend.qor.selectcore.replicator bottomsheetBeforeSend.qor.bottomsheets.replicator',
|
||||||
|
EVENT_REPLICATOR_ADDED = 'added.' + NAMESPACE,
|
||||||
|
EVENT_REPLICATORS_ADDED = 'addedMultiple.' + NAMESPACE,
|
||||||
|
EVENT_REPLICATORS_ADDED_DONE = 'addedMultipleDone.' + NAMESPACE,
|
||||||
|
CLASS_CONTAINER = '.qor-fieldset-container';
|
||||||
|
|
||||||
|
function QorReplicator(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorReplicator.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.index = 0;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorReplicator.prototype = {
|
||||||
|
constructor: QorReplicator,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
let $element = this.$element,
|
||||||
|
$template = $element.find('> .qor-field__block > .qor-fieldset--new'),
|
||||||
|
fieldsetName;
|
||||||
|
|
||||||
|
this.singlePage = !($element.closest('.qor-slideout').length && $element.closest('.qor-bottomsheets').length);
|
||||||
|
this.maxitems = $element.data('maxItem');
|
||||||
|
this.isSortable = $element.hasClass('qor-fieldset-sortable');
|
||||||
|
|
||||||
|
if (!$template.length || $element.closest('.qor-fieldset--new').length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should destroy all components here
|
||||||
|
$template.trigger('disable');
|
||||||
|
// remove data-select2-id attribute or select2 will disable all previous instance
|
||||||
|
$template.find('select[data-toggle]').removeAttr('data-select2-id');
|
||||||
|
|
||||||
|
// if have isMultiple data value or template length large than 1
|
||||||
|
this.isMultipleTemplate = $element.data('isMultiple');
|
||||||
|
|
||||||
|
if (this.isMultipleTemplate) {
|
||||||
|
this.fieldsetName = [];
|
||||||
|
this.template = {};
|
||||||
|
this.index = [];
|
||||||
|
|
||||||
|
$template.each((i, ele) => {
|
||||||
|
fieldsetName = $(ele).data('fieldsetName');
|
||||||
|
if (fieldsetName) {
|
||||||
|
this.template[fieldsetName] = $(ele).prop('outerHTML');
|
||||||
|
this.fieldsetName.push(fieldsetName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.parseMultiple();
|
||||||
|
} else {
|
||||||
|
this.parse($template.prop('outerHTML'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$template.hide();
|
||||||
|
this.bind();
|
||||||
|
this.resetButton();
|
||||||
|
this.resetPositionButton();
|
||||||
|
},
|
||||||
|
|
||||||
|
resetPositionButton: function() {
|
||||||
|
let sortableButton = this.$element.find('> .qor-sortable__button');
|
||||||
|
|
||||||
|
if (this.isSortable) {
|
||||||
|
if (this.getCurrentItems() > 1) {
|
||||||
|
sortableButton.show();
|
||||||
|
} else {
|
||||||
|
sortableButton.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getCurrentItems: function() {
|
||||||
|
return this.$element.find('> .qor-field__block > .qor-fieldset').not('.qor-fieldset--new,.is-deleted').length;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleButton: function(isHide) {
|
||||||
|
let $button = this.$element.find('> .qor-field__block > .qor-fieldset__add');
|
||||||
|
|
||||||
|
if (isHide) {
|
||||||
|
$button.hide();
|
||||||
|
} else {
|
||||||
|
$button.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resetButton: function() {
|
||||||
|
if (this.maxitems <= this.getCurrentItems()) {
|
||||||
|
this.toggleButton(true);
|
||||||
|
} else {
|
||||||
|
this.toggleButton();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
parse: function($tmp) {
|
||||||
|
let template;
|
||||||
|
|
||||||
|
if (!$tmp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
template = this.initTemplate($tmp);
|
||||||
|
|
||||||
|
this.template = template.template;
|
||||||
|
this.index = template.index;
|
||||||
|
},
|
||||||
|
|
||||||
|
parseMultiple: function() {
|
||||||
|
let template,
|
||||||
|
name,
|
||||||
|
fieldsetName = this.fieldsetName;
|
||||||
|
|
||||||
|
for (let i = 0, len = fieldsetName.length; i < len; i++) {
|
||||||
|
name = fieldsetName[i];
|
||||||
|
template = this.initTemplate(this.template[name]);
|
||||||
|
this.template[name] = template.template;
|
||||||
|
this.index.push(template.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.multipleIndex = _.max(this.index);
|
||||||
|
},
|
||||||
|
|
||||||
|
initTemplate: function(template) {
|
||||||
|
let i,
|
||||||
|
deepLevel = this.$element.parents(CLASS_CONTAINER).length;
|
||||||
|
|
||||||
|
template = template.replace(/(\w+)\="(\S*\[\d+\]\S*)"/g, function(attribute, name, value) {
|
||||||
|
value = value.replace(/^(\S*)\[(\d+)\]([^\[\]]*)$/, function(input, prefix, index) {
|
||||||
|
if (input === value) {
|
||||||
|
if (name === 'name' && !i) {
|
||||||
|
i = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deepLevel) {
|
||||||
|
// assume input = QorResource.SerializableMeta.Menus[1].SubMenus[2].Items[3].URL
|
||||||
|
// if deepLevel = 1, input should be QorResource.SerializableMeta.Menus[1].SubMenus[{{index}}].Items[3].URL
|
||||||
|
// if deepLevel = 2, input should be QorResource.SerializableMeta.Menus[1].SubMenus[2].Items[{{index}}].URL
|
||||||
|
|
||||||
|
let newInput = '',
|
||||||
|
splitStr = input.split(/\[\d+\]/), // ["QorResource.SerializableMeta.Menus", ".SubMenus", ".Items", ".URL"]
|
||||||
|
sortNumbers = input.match(/\[\d+\]/g); // ["[1]", "[2]", "[3]"]
|
||||||
|
|
||||||
|
for (let j = 0; j < splitStr.length; j++) {
|
||||||
|
let str = '';
|
||||||
|
if (j === deepLevel) {
|
||||||
|
str = '[{{index}}]';
|
||||||
|
} else if (j < sortNumbers.length) {
|
||||||
|
str = sortNumbers[j];
|
||||||
|
}
|
||||||
|
newInput += splitStr[j] + str;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newInput;
|
||||||
|
} else {
|
||||||
|
return input.replace(/\[\d+\]/, '[{{index}}]');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return name + '="' + value + '"';
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
template: template,
|
||||||
|
index: parseFloat(i) + 5 //make sure the index is different from original.
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
let options = this.options;
|
||||||
|
|
||||||
|
this.$element.on(EVENT_CLICK, options.addClass, $.proxy(this.add, this)).on(EVENT_CLICK, options.delClass, $.proxy(this.del, this));
|
||||||
|
|
||||||
|
this.singlePage && $(document).on(EVENT_SUBMIT, '.mdl-layout__container form', this.clearFieldData);
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_SLIDEOUTBEFORESEND, '.qor-slideout', this.clearFieldDataInSlideout)
|
||||||
|
.on(EVENT_SELECTCOREBEFORESEND, this.clearFieldDataInBottomsheet);
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element.off(EVENT_CLICK);
|
||||||
|
|
||||||
|
this.singlePage && $(document).off(EVENT_SUBMIT, '.mdl-layout__container form', this.clearFieldData);
|
||||||
|
$(document)
|
||||||
|
.off(EVENT_SLIDEOUTBEFORESEND, '.qor-slideout', this.clearFieldDataInSlideout)
|
||||||
|
.off(EVENT_SELECTCOREBEFORESEND, this.clearFieldDataInBottomsheet);
|
||||||
|
},
|
||||||
|
|
||||||
|
clearFieldData: function() {
|
||||||
|
$('.qor-fieldset--new').remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
clearFieldDataInSlideout: function() {
|
||||||
|
$('.qor-slideout .qor-fieldset--new').remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
clearFieldDataInBottomsheet: function() {
|
||||||
|
$('.qor-bottomsheets .qor-fieldset--new').remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
add: function(e, data, isAutomatically) {
|
||||||
|
let options = this.options,
|
||||||
|
$item,
|
||||||
|
template,
|
||||||
|
$target = $(e.target).closest(options.addClass);
|
||||||
|
|
||||||
|
if (this.maxitems <= this.getCurrentItems()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isMultipleTemplate) {
|
||||||
|
let templateName = $target.data('template'),
|
||||||
|
parents = $target.closest(this.$element),
|
||||||
|
parentsChildren = parents.children(options.childrenClass),
|
||||||
|
$fieldset = $target.closest(options.childrenClass).children('fieldset');
|
||||||
|
|
||||||
|
template = this.template[templateName];
|
||||||
|
$item = $(template.replace(/\{\{index\}\}/g, this.multipleIndex));
|
||||||
|
|
||||||
|
// get input kind from add button then add into QorResource.Rules[1].Kind input
|
||||||
|
for (let dataKey in $target.data()) {
|
||||||
|
if (dataKey.match(/^sync/)) {
|
||||||
|
let k = dataKey.replace(/^sync/, '');
|
||||||
|
$item.find("input[name*='." + k + "']").val($target.data(dataKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fieldset.length) {
|
||||||
|
$fieldset.last().after($item.show());
|
||||||
|
} else {
|
||||||
|
parentsChildren.prepend($item.show());
|
||||||
|
}
|
||||||
|
$item.data('itemIndex', this.multipleIndex).removeClass('qor-fieldset--new');
|
||||||
|
this.multipleIndex++;
|
||||||
|
} else {
|
||||||
|
if (!isAutomatically) {
|
||||||
|
$item = this.addSingle();
|
||||||
|
$target.before($item.show());
|
||||||
|
this.index++;
|
||||||
|
} else {
|
||||||
|
if (data && data.length) {
|
||||||
|
this.addMultiple(data);
|
||||||
|
$(document).trigger(EVENT_REPLICATORS_ADDED_DONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isAutomatically) {
|
||||||
|
$item.trigger('enable');
|
||||||
|
$(document).trigger(EVENT_REPLICATOR_ADDED, [$item]);
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resetPositionButton();
|
||||||
|
this.resetButton();
|
||||||
|
},
|
||||||
|
|
||||||
|
addMultiple: function(data) {
|
||||||
|
let $item;
|
||||||
|
|
||||||
|
for (let i = 0, len = data.length; i < len; i++) {
|
||||||
|
$item = this.addSingle();
|
||||||
|
this.index++;
|
||||||
|
$(document).trigger(EVENT_REPLICATORS_ADDED, [$item, data[i]]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addSingle: function() {
|
||||||
|
let $item,
|
||||||
|
$element = this.$element;
|
||||||
|
|
||||||
|
if (!this.template) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = $(this.template.replace(/\{\{index\}\}/g, this.index));
|
||||||
|
// add order property for sortable fieldset
|
||||||
|
if (this.isSortable) {
|
||||||
|
let order = $element.find('> .qor-field__block > .qor-sortable__item').not('.qor-fieldset--new').length;
|
||||||
|
$item
|
||||||
|
.attr('order-index', order)
|
||||||
|
.attr('order-item', `item_${order}`)
|
||||||
|
.css('order', order);
|
||||||
|
}
|
||||||
|
|
||||||
|
$item.data('itemIndex', this.index).removeClass('qor-fieldset--new');
|
||||||
|
|
||||||
|
return $item;
|
||||||
|
},
|
||||||
|
|
||||||
|
del: function(e) {
|
||||||
|
let options = this.options,
|
||||||
|
$item = $(e.target).closest(options.itemClass),
|
||||||
|
$alert,
|
||||||
|
that = this,
|
||||||
|
message = {
|
||||||
|
confirm:
|
||||||
|
$(e.target)
|
||||||
|
.closest(options.delClass)
|
||||||
|
.data('confirm') || 'Are you sure?'
|
||||||
|
};
|
||||||
|
|
||||||
|
QOR.qorConfirm(message, function(confirm) {
|
||||||
|
if (confirm) {
|
||||||
|
$item
|
||||||
|
.addClass('is-deleted')
|
||||||
|
.children(':visible')
|
||||||
|
.addClass('hidden')
|
||||||
|
.hide();
|
||||||
|
$alert = $(options.alertTemplate.replace('{{name}}', that.parseName($item)));
|
||||||
|
$alert.find(options.undoClass).one(
|
||||||
|
EVENT_CLICK,
|
||||||
|
function() {
|
||||||
|
if (that.maxitems <= that.getCurrentItems()) {
|
||||||
|
window.QOR.qorConfirm(that.$element.data('maxItemHint'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item.find('> .qor-fieldset__alert').remove();
|
||||||
|
$item
|
||||||
|
.removeClass('is-deleted')
|
||||||
|
.children('.hidden')
|
||||||
|
.removeClass('hidden')
|
||||||
|
.show();
|
||||||
|
that.resetButton();
|
||||||
|
that.resetPositionButton();
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
that.resetButton();
|
||||||
|
that.resetPositionButton();
|
||||||
|
$item.append($alert);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
parseName: function($item) {
|
||||||
|
let name = $item.find('input[name]').attr('name') || $item.find('textarea[name]').attr('name');
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
return name.replace(/[^\[\]]+$/, '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorReplicator.DEFAULTS = {
|
||||||
|
itemClass: '.qor-fieldset',
|
||||||
|
newClass: '.qor-fieldset--new',
|
||||||
|
addClass: '.qor-fieldset__add',
|
||||||
|
delClass: '.qor-fieldset__delete',
|
||||||
|
childrenClass: '.qor-field__block',
|
||||||
|
undoClass: '.qor-fieldset__undo',
|
||||||
|
alertTemplate:
|
||||||
|
'<div class="qor-fieldset__alert">' +
|
||||||
|
'<input type="hidden" name="{{name}}._destroy" value="1">' +
|
||||||
|
'<button class="mdl-button mdl-button--accent mdl-js-button mdl-js-ripple-effect qor-fieldset__undo" type="button">Undo delete</button>' +
|
||||||
|
'</div>'
|
||||||
|
};
|
||||||
|
|
||||||
|
QorReplicator.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
data = $this.data(NAMESPACE),
|
||||||
|
fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
$this.data(NAMESPACE, (data = new QorReplicator(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.call(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
let selector = CLASS_CONTAINER;
|
||||||
|
let options = {};
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorReplicator.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorReplicator.plugin.call($(selector, e.target), options);
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorReplicator;
|
||||||
|
});
|
||||||
163
app/views/qor/assets/javascripts/qor/qor-search.js
Normal file
163
app/views/qor/assets/javascripts/qor/qor-search.js
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
(function (factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function ($) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
var location = window.location;
|
||||||
|
var componentHandler = window.componentHandler;
|
||||||
|
var history = window.history;
|
||||||
|
var NAMESPACE = 'qor.globalSearch';
|
||||||
|
var EVENT_ENABLE = 'enable.' + NAMESPACE;
|
||||||
|
var EVENT_DISABLE = 'disable.' + NAMESPACE;
|
||||||
|
var EVENT_CLICK = 'click.' + NAMESPACE;
|
||||||
|
|
||||||
|
var SEARCH_RESOURCE = '.qor-global-search--resource';
|
||||||
|
var SEARCH_RESULTS = '.qor-global-search--results';
|
||||||
|
var QOR_TABLE = '.qor-table';
|
||||||
|
var IS_ACTIVE = 'is-active';
|
||||||
|
|
||||||
|
function QorSearchCenter(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorSearchCenter.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorSearchCenter.prototype = {
|
||||||
|
constructor: QorSearchCenter,
|
||||||
|
|
||||||
|
init: function () {
|
||||||
|
this.bind();
|
||||||
|
this.initTab();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function () {
|
||||||
|
this.$element.on(EVENT_CLICK, $.proxy(this.click, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function () {
|
||||||
|
this.$element.off(EVENT_CLICK, this.check);
|
||||||
|
},
|
||||||
|
|
||||||
|
initTab: function () {
|
||||||
|
var locationSearch = location.search;
|
||||||
|
var resourceName;
|
||||||
|
if (/resource_name/.test(locationSearch)){
|
||||||
|
resourceName = locationSearch.match(/resource_name=\w+/g).toString().split('=')[1];
|
||||||
|
$(SEARCH_RESOURCE).removeClass(IS_ACTIVE);
|
||||||
|
$('[data-resource="' + resourceName + '"]').addClass(IS_ACTIVE);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
click : function (e) {
|
||||||
|
var $target = $(e.target);
|
||||||
|
var data = $target.data();
|
||||||
|
|
||||||
|
if ($target.is(SEARCH_RESOURCE)){
|
||||||
|
var oldUrl = location.href.replace(/#/g, '');
|
||||||
|
var newUrl;
|
||||||
|
var newResourceName = data.resource;
|
||||||
|
var hasResource = /resource_name/.test(oldUrl);
|
||||||
|
var hasKeyword = /keyword/.test(oldUrl);
|
||||||
|
var resourceParam = 'resource_name=' + newResourceName;
|
||||||
|
var searchSymbol = hasKeyword ? '&' : '?keyword=&';
|
||||||
|
|
||||||
|
if (newResourceName){
|
||||||
|
if (hasResource){
|
||||||
|
newUrl = oldUrl.replace(/resource_name=\w+/g, resourceParam);
|
||||||
|
} else {
|
||||||
|
newUrl = oldUrl + searchSymbol + resourceParam;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newUrl = oldUrl.replace(/&resource_name=\w+/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (history.pushState){
|
||||||
|
this.fetchSearch(newUrl, $target);
|
||||||
|
} else {
|
||||||
|
location.href = newUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchSearch: function (url,$target) {
|
||||||
|
var title = document.title;
|
||||||
|
|
||||||
|
$.ajax(url, {
|
||||||
|
method: 'GET',
|
||||||
|
dataType: 'html',
|
||||||
|
beforeSend: function () {
|
||||||
|
$('.mdl-spinner').remove();
|
||||||
|
$(SEARCH_RESULTS).prepend('<div class="mdl-spinner mdl-js-spinner is-active"></div>').find('.qor-section').hide();
|
||||||
|
componentHandler.upgradeElement(document.querySelector('.mdl-spinner'));
|
||||||
|
},
|
||||||
|
success: function (html) {
|
||||||
|
var result = $(html).find(SEARCH_RESULTS).html();
|
||||||
|
$(SEARCH_RESOURCE).removeClass(IS_ACTIVE);
|
||||||
|
$target.addClass(IS_ACTIVE);
|
||||||
|
// change location URL without refresh page
|
||||||
|
history.pushState({ Page: url, Title: title }, title, url);
|
||||||
|
$('.mdl-spinner').remove();
|
||||||
|
$(SEARCH_RESULTS).removeClass('loading').html(result);
|
||||||
|
componentHandler.upgradeElements(document.querySelectorAll(QOR_TABLE));
|
||||||
|
},
|
||||||
|
error: function (xhr, textStatus, errorThrown) {
|
||||||
|
$(SEARCH_RESULTS).find('.qor-section').show();
|
||||||
|
$('.mdl-spinner').remove();
|
||||||
|
window.alert([textStatus, errorThrown].join(': '));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSearchCenter.DEFAULTS = {
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSearchCenter.plugin = function (options) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
$this.data(NAMESPACE, (data = new QorSearchCenter(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction(fn = data[options])) {
|
||||||
|
fn.call(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
var selector = '[data-toggle="qor.global.search"]';
|
||||||
|
var options = {};
|
||||||
|
|
||||||
|
$(document).
|
||||||
|
on(EVENT_DISABLE, function (e) {
|
||||||
|
QorSearchCenter.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
}).
|
||||||
|
on(EVENT_ENABLE, function (e) {
|
||||||
|
QorSearchCenter.plugin.call($(selector, e.target), options);
|
||||||
|
}).
|
||||||
|
triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorSearchCenter;
|
||||||
|
|
||||||
|
});
|
||||||
170
app/views/qor/assets/javascripts/qor/qor-select-core.js
Normal file
170
app/views/qor/assets/javascripts/qor/qor-select-core.js
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let FormData = window.FormData,
|
||||||
|
QOR = window.QOR,
|
||||||
|
NAMESPACE = 'qor.selectcore',
|
||||||
|
EVENT_SELECTCORE_BEFORESEND = 'selectcoreBeforeSend.' + NAMESPACE,
|
||||||
|
EVENT_ONSELECT = 'afterSelected.' + NAMESPACE,
|
||||||
|
EVENT_ONSUBMIT = 'afterSubmitted.' + NAMESPACE,
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
EVENT_SUBMIT = 'submit.' + NAMESPACE,
|
||||||
|
CLASS_TABLE = 'table.qor-js-table tr',
|
||||||
|
CLASS_FORM = 'form';
|
||||||
|
|
||||||
|
function QorSelectCore(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorSelectCore.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorSelectCore.prototype = {
|
||||||
|
constructor: QorSelectCore,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$element.on(EVENT_CLICK, CLASS_TABLE, this.processingData.bind(this)).on(EVENT_SUBMIT, CLASS_FORM, this.submit.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element.off(EVENT_CLICK, CLASS_TABLE).off(EVENT_SUBMIT, CLASS_FORM);
|
||||||
|
},
|
||||||
|
|
||||||
|
processingData: function(e) {
|
||||||
|
let $this = $(e.target).closest('tr'),
|
||||||
|
$bottomsheets = $this.closest('.qor-bottomsheets'),
|
||||||
|
data = {},
|
||||||
|
url,
|
||||||
|
options = this.options,
|
||||||
|
onSelect = options.onSelect,
|
||||||
|
loading = options.loading;
|
||||||
|
|
||||||
|
data = $.extend({}, data, $this.data());
|
||||||
|
data.$clickElement = $this;
|
||||||
|
|
||||||
|
url = data.mediaLibraryUrl || data.url;
|
||||||
|
|
||||||
|
if (loading && $.isFunction(loading)) {
|
||||||
|
loading($bottomsheets);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
|
||||||
|
$.getJSON(url, function(json) {
|
||||||
|
json.MediaOption && (json.MediaOption = JSON.parse(json.MediaOption));
|
||||||
|
data = $.extend({}, json, data);
|
||||||
|
if (onSelect && $.isFunction(onSelect)) {
|
||||||
|
onSelect(data, e);
|
||||||
|
$(document).trigger(EVENT_ONSELECT);
|
||||||
|
}
|
||||||
|
}).always(function() {
|
||||||
|
$bottomsheets.find('.qor-media-loading').remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (onSelect && $.isFunction(onSelect)) {
|
||||||
|
onSelect(data, e);
|
||||||
|
$(document).trigger(EVENT_ONSELECT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
submit: function(e) {
|
||||||
|
let form = e.target,
|
||||||
|
$form = $(form),
|
||||||
|
_this = this,
|
||||||
|
$submit = $form.find(':submit'),
|
||||||
|
data,
|
||||||
|
$loading = $(QOR.$formLoading),
|
||||||
|
onSubmit = this.options.onSubmit;
|
||||||
|
|
||||||
|
$(document).trigger(EVENT_SELECTCORE_BEFORESEND);
|
||||||
|
|
||||||
|
$form.find('.qor-fieldset--new').remove();
|
||||||
|
|
||||||
|
if (FormData) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
$.ajax($form.prop('action'), {
|
||||||
|
method: $form.prop('method'),
|
||||||
|
data: new FormData(form),
|
||||||
|
dataType: 'json',
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
beforeSend: function() {
|
||||||
|
$('.qor-submit-loading').remove();
|
||||||
|
$loading.appendTo($submit.prop('disabled', true).closest('.qor-form__actions')).trigger('enable.qor.material');
|
||||||
|
},
|
||||||
|
success: function(json) {
|
||||||
|
json.MediaOption && (json.MediaOption = JSON.parse(json.MediaOption));
|
||||||
|
data = json;
|
||||||
|
data.primaryKey = data.ID;
|
||||||
|
|
||||||
|
$('.qor-error').remove();
|
||||||
|
|
||||||
|
if (onSubmit && $.isFunction(onSubmit)) {
|
||||||
|
onSubmit(data, e);
|
||||||
|
$(document).trigger(EVENT_ONSUBMIT);
|
||||||
|
} else {
|
||||||
|
_this.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(err) {
|
||||||
|
QOR.handleAjaxError(err);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
$submit.prop('disabled', false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh: function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
window.location.reload();
|
||||||
|
}, 350);
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSelectCore.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
let $this = $(this),
|
||||||
|
data = $this.data(NAMESPACE),
|
||||||
|
fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this.data(NAMESPACE, (data = new QorSelectCore(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.qorSelectCore = QorSelectCore.plugin;
|
||||||
|
|
||||||
|
return QorSelectCore;
|
||||||
|
});
|
||||||
339
app/views/qor/assets/javascripts/qor/qor-select-many.js
Normal file
339
app/views/qor/assets/javascripts/qor/qor-select-many.js
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let $body = $('body'),
|
||||||
|
$document = $(document),
|
||||||
|
Mustache = window.Mustache,
|
||||||
|
NAMESPACE = 'qor.selectone',
|
||||||
|
PARENT_NAMESPACE = 'qor.bottomsheets',
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_RELOAD = 'reload.' + PARENT_NAMESPACE,
|
||||||
|
CLASS_CLEAR_SELECT = '.qor-selected-many__remove',
|
||||||
|
CLASS_UNDO_DELETE = '.qor-selected-many__undo',
|
||||||
|
CLASS_DELETED_ITEM = 'qor-selected-many__deleted',
|
||||||
|
CLASS_SELECT_FIELD = '.qor-field__selected-many',
|
||||||
|
CLASS_SELECT_INPUT = '.qor-field__selectmany-input',
|
||||||
|
CLASS_SELECT_ICON = '.qor-select__select-icon',
|
||||||
|
CLASS_SELECT_HINT = '.qor-selectmany__hint',
|
||||||
|
CLASS_SELECT_ALL = '.qor-selectmany__selectall',
|
||||||
|
CLASS_PARENT = '.qor-field__selectmany',
|
||||||
|
CLASS_SELECTED = 'is_selected',
|
||||||
|
CLASS_MANY = 'qor-bottomsheets__select-many';
|
||||||
|
|
||||||
|
function QorSelectMany(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorSelectMany.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorSelectMany.prototype = {
|
||||||
|
constructor: QorSelectMany,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
$document.on(EVENT_RELOAD, `.${CLASS_MANY}`, this.reloadData.bind(this));
|
||||||
|
|
||||||
|
this.$element
|
||||||
|
.on(EVENT_CLICK, CLASS_CLEAR_SELECT, this.clearSelect.bind(this))
|
||||||
|
.on(EVENT_CLICK, '[data-select-modal="many"]', this.openBottomSheets.bind(this))
|
||||||
|
.on(EVENT_CLICK, CLASS_UNDO_DELETE, this.undoDelete.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
$document.off(EVENT_CLICK, '[data-select-modal="many"]').off(EVENT_RELOAD, `.${CLASS_MANY}`);
|
||||||
|
this.$element.off(EVENT_CLICK, CLASS_CLEAR_SELECT).off(EVENT_CLICK, CLASS_UNDO_DELETE);
|
||||||
|
},
|
||||||
|
|
||||||
|
clearSelect: function(e) {
|
||||||
|
var $target = $(e.target),
|
||||||
|
$selectFeild = $target.closest(CLASS_PARENT);
|
||||||
|
|
||||||
|
$target.closest('[data-primary-key]').addClass(CLASS_DELETED_ITEM);
|
||||||
|
this.updateSelectInputData($selectFeild);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
undoDelete: function(e) {
|
||||||
|
var $target = $(e.target),
|
||||||
|
$selectFeild = $target.closest(CLASS_PARENT);
|
||||||
|
|
||||||
|
$target.closest('[data-primary-key]').removeClass(CLASS_DELETED_ITEM);
|
||||||
|
this.updateSelectInputData($selectFeild);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
openBottomSheets: function(e) {
|
||||||
|
let $this = $(e.target),
|
||||||
|
data = $this.data();
|
||||||
|
|
||||||
|
this.BottomSheets = $body.data('qor.bottomsheets');
|
||||||
|
this.bottomsheetsData = data;
|
||||||
|
|
||||||
|
this.$selector = data.selectId ? $(data.selectId) : $this.closest(CLASS_PARENT).find('select');
|
||||||
|
this.$selectFeild = this.$selector.closest(CLASS_PARENT).find(CLASS_SELECT_FIELD);
|
||||||
|
|
||||||
|
// select many templates
|
||||||
|
this.SELECT_MANY_SELECTED_ICON = $('[name="select-many-selected-icon"]').html();
|
||||||
|
this.SELECT_MANY_UNSELECTED_ICON = $('[name="select-many-unselected-icon"]').html();
|
||||||
|
this.SELECT_MANY_HINT = $('[name="select-many-hint"]').html();
|
||||||
|
this.SELECT_MANY_TEMPLATE = $('[name="select-many-template"]').html();
|
||||||
|
|
||||||
|
data.url = data.selectListingUrl;
|
||||||
|
|
||||||
|
if (data.selectDefaultCreating) {
|
||||||
|
data.url = data.selectCreatingUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.BottomSheets.open(data, this.handleSelectMany.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
reloadData: function() {
|
||||||
|
this.initItems();
|
||||||
|
},
|
||||||
|
|
||||||
|
renderSelectMany: function(data) {
|
||||||
|
return Mustache.render(this.SELECT_MANY_TEMPLATE, data);
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHint: function(data) {
|
||||||
|
return Mustache.render(this.SELECT_MANY_HINT, data);
|
||||||
|
},
|
||||||
|
|
||||||
|
initItems: function() {
|
||||||
|
var $tr = this.$bottomsheets.find('tbody tr'),
|
||||||
|
selectedIconTmpl = this.SELECT_MANY_SELECTED_ICON,
|
||||||
|
unSelectedIconTmpl = this.SELECT_MANY_UNSELECTED_ICON,
|
||||||
|
selectedIDs = [],
|
||||||
|
primaryKey,
|
||||||
|
$selectedItems = this.$selectFeild.find('[data-primary-key]').not('.' + CLASS_DELETED_ITEM);
|
||||||
|
|
||||||
|
$selectedItems.each(function() {
|
||||||
|
selectedIDs.push($(this).data().primaryKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
$tr.each(function() {
|
||||||
|
var $this = $(this),
|
||||||
|
$td = $this.find('td:first');
|
||||||
|
|
||||||
|
primaryKey = $this.data().primaryKey;
|
||||||
|
|
||||||
|
if (selectedIDs.indexOf(primaryKey) != '-1') {
|
||||||
|
$this.addClass(CLASS_SELECTED);
|
||||||
|
$td.append(selectedIconTmpl);
|
||||||
|
} else {
|
||||||
|
$td.append(unSelectedIconTmpl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.updateHint(this.getSelectedItemData());
|
||||||
|
},
|
||||||
|
|
||||||
|
getSelectedItemData: function() {
|
||||||
|
var selecedItems = this.$selectFeild.find('[data-primary-key]').not('.' + CLASS_DELETED_ITEM);
|
||||||
|
return {
|
||||||
|
selectedNum: selecedItems.length
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
updateHint: function(data) {
|
||||||
|
var template;
|
||||||
|
|
||||||
|
$.extend(data, this.bottomsheetsData);
|
||||||
|
template = this.renderHint(data);
|
||||||
|
|
||||||
|
this.$bottomsheets.find(CLASS_SELECT_HINT).remove();
|
||||||
|
this.$bottomsheets.find('.qor-page__body').before(template);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateSelectInputData: function($selectFeild) {
|
||||||
|
var $selectList = $selectFeild ? $selectFeild : this.$selectFeild,
|
||||||
|
$selectedItems = $selectList.find('[data-primary-key]').not('.' + CLASS_DELETED_ITEM),
|
||||||
|
$selector = $selectFeild ? $selectFeild.find(CLASS_SELECT_INPUT) : this.$selector,
|
||||||
|
$options = $selector.find('option'),
|
||||||
|
$option,
|
||||||
|
data,
|
||||||
|
primaryKey;
|
||||||
|
|
||||||
|
$options.prop('selected', false);
|
||||||
|
|
||||||
|
$selectedItems.each(function() {
|
||||||
|
primaryKey = $(this).data().primaryKey;
|
||||||
|
$option = $options.filter('[value="' + primaryKey + '"]');
|
||||||
|
|
||||||
|
if (!$option.length) {
|
||||||
|
data = {
|
||||||
|
primaryKey: primaryKey,
|
||||||
|
displayName: ''
|
||||||
|
};
|
||||||
|
$option = $(Mustache.render(QorSelectMany.SELECT_MANY_OPTION_TEMPLATE, data));
|
||||||
|
$selector.append($option);
|
||||||
|
}
|
||||||
|
|
||||||
|
$option.prop('selected', true);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
changeIcon: function($ele, template) {
|
||||||
|
$ele.find(CLASS_SELECT_ICON).remove();
|
||||||
|
$ele.find('td:first').prepend(template);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeItem: function(data) {
|
||||||
|
var primaryKey = data.primaryKey;
|
||||||
|
|
||||||
|
this.$selectFeild
|
||||||
|
.find('[data-primary-key="' + primaryKey + '"]')
|
||||||
|
.find(CLASS_CLEAR_SELECT)
|
||||||
|
.click();
|
||||||
|
this.changeIcon(data.$clickElement, this.SELECT_MANY_UNSELECTED_ICON);
|
||||||
|
},
|
||||||
|
|
||||||
|
addItem: function(data, isNewData) {
|
||||||
|
var template = this.renderSelectMany(data),
|
||||||
|
$option,
|
||||||
|
$list = this.$selectFeild.find('[data-primary-key="' + data.primaryKey + '"]');
|
||||||
|
|
||||||
|
if ($list.length) {
|
||||||
|
if ($list.hasClass(CLASS_DELETED_ITEM)) {
|
||||||
|
$list.removeClass(CLASS_DELETED_ITEM);
|
||||||
|
this.updateSelectInputData();
|
||||||
|
this.changeIcon(data.$clickElement, this.SELECT_MANY_SELECTED_ICON);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$selectFeild.append(template);
|
||||||
|
|
||||||
|
if (isNewData) {
|
||||||
|
$option = $(Mustache.render(QorSelectMany.SELECT_MANY_OPTION_TEMPLATE, data));
|
||||||
|
$option.appendTo(this.$selector);
|
||||||
|
$option.prop('selected', true);
|
||||||
|
this.$bottomsheets.remove();
|
||||||
|
if (!$('.qor-bottomsheets').is(':visible')) {
|
||||||
|
$('body').removeClass('qor-bottomsheets-open');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changeIcon(data.$clickElement, this.SELECT_MANY_SELECTED_ICON);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSelectMany: function($bottomsheets) {
|
||||||
|
let options = {
|
||||||
|
onSelect: this.onSelectResults.bind(this), // render selected item after click item lists
|
||||||
|
onSubmit: this.onSubmitResults.bind(this) // render new items after new item form submitted
|
||||||
|
};
|
||||||
|
|
||||||
|
$bottomsheets.qorSelectCore(options).addClass(CLASS_MANY);
|
||||||
|
$bottomsheets.on(EVENT_CLICK, CLASS_SELECT_ALL, this.handleSelectAll.bind(this));
|
||||||
|
this.$bottomsheets = $bottomsheets;
|
||||||
|
this.initItems();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSelectAll: function() {
|
||||||
|
let $trs = this.$bottomsheets.find('.qor-table tbody tr'),
|
||||||
|
$trsHasUnselected = $trs.not('.is_selected');
|
||||||
|
|
||||||
|
if ($trsHasUnselected.length) {
|
||||||
|
$trsHasUnselected.click();
|
||||||
|
} else {
|
||||||
|
$trs.click();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelectResults: function(data) {
|
||||||
|
this.handleResults(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSubmitResults: function(data) {
|
||||||
|
this.handleResults(data, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleResults: function(data, isNewData) {
|
||||||
|
data.displayName = data.Text || data.Name || data.Title || data.Code || data[Object.keys(data)[0]];
|
||||||
|
|
||||||
|
data.displayName = (data.displayName).escapeSymbol();
|
||||||
|
|
||||||
|
if (isNewData) {
|
||||||
|
this.addItem(data, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $element = data.$clickElement,
|
||||||
|
isSelected;
|
||||||
|
|
||||||
|
$element.toggleClass(CLASS_SELECTED);
|
||||||
|
isSelected = $element.hasClass(CLASS_SELECTED);
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
this.addItem(data);
|
||||||
|
} else {
|
||||||
|
this.removeItem(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateHint(this.getSelectedItemData());
|
||||||
|
this.updateSelectInputData();
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSelectMany.SELECT_MANY_OPTION_TEMPLATE = '<option value="[[ primaryKey ]]" >[[ displayName ]]</option>';
|
||||||
|
|
||||||
|
QorSelectMany.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorSelectMany(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = '[data-toggle="qor.selectmany"]';
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorSelectMany.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorSelectMany.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorSelectMany;
|
||||||
|
});
|
||||||
214
app/views/qor/assets/javascripts/qor/qor-select-one.js
Normal file
214
app/views/qor/assets/javascripts/qor/qor-select-one.js
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let $body = $('body'),
|
||||||
|
$document = $(document),
|
||||||
|
Mustache = window.Mustache,
|
||||||
|
NAMESPACE = 'qor.selectone',
|
||||||
|
PARENT_NAMESPACE = 'qor.bottomsheets',
|
||||||
|
EVENT_CLICK = 'click.' + NAMESPACE,
|
||||||
|
EVENT_ENABLE = 'enable.' + NAMESPACE,
|
||||||
|
EVENT_DISABLE = 'disable.' + NAMESPACE,
|
||||||
|
EVENT_RELOAD = 'reload.' + PARENT_NAMESPACE,
|
||||||
|
CLASS_CLEAR_SELECT = '.qor-selected__remove',
|
||||||
|
CLASS_CHANGE_SELECT = '.qor-selected__change',
|
||||||
|
CLASS_SELECT_FIELD = '.qor-field__selected',
|
||||||
|
CLASS_SELECT_INPUT = '.qor-field__selectone-input',
|
||||||
|
CLASS_SELECT_TRIGGER = '.qor-field__selectone-trigger',
|
||||||
|
CLASS_PARENT = '.qor-field__selectone',
|
||||||
|
CLASS_SELECTED = 'is_selected',
|
||||||
|
CLASS_ONE = 'qor-bottomsheets__select-one';
|
||||||
|
|
||||||
|
function QorSelectOne(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorSelectOne.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorSelectOne.prototype = {
|
||||||
|
constructor: QorSelectOne,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
$document.on(EVENT_RELOAD, `.${CLASS_ONE}`, this.reloadData.bind(this));
|
||||||
|
this.$element
|
||||||
|
.on(EVENT_CLICK, CLASS_CLEAR_SELECT, this.clearSelect.bind(this))
|
||||||
|
.on(EVENT_CLICK, '[data-selectone-url]', this.openBottomSheets.bind(this))
|
||||||
|
.on(EVENT_CLICK, CLASS_CHANGE_SELECT, this.changeSelect);
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
$document.off(EVENT_CLICK, '[data-selectone-url]').off(EVENT_RELOAD, `.${CLASS_ONE}`);
|
||||||
|
this.$element.off(EVENT_CLICK, CLASS_CLEAR_SELECT).off(EVENT_CLICK, CLASS_CHANGE_SELECT);
|
||||||
|
},
|
||||||
|
|
||||||
|
clearSelect: function(e) {
|
||||||
|
var $target = $(e.target),
|
||||||
|
$parent = $target.closest(CLASS_PARENT);
|
||||||
|
|
||||||
|
$parent.find(CLASS_SELECT_FIELD).remove();
|
||||||
|
$parent.find(CLASS_SELECT_INPUT).html('');
|
||||||
|
$parent.find(CLASS_SELECT_INPUT)[0].value = '';
|
||||||
|
$parent.find(CLASS_SELECT_TRIGGER).show();
|
||||||
|
|
||||||
|
$parent.trigger('qor.selectone.unselected');
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
changeSelect: function() {
|
||||||
|
var $target = $(this),
|
||||||
|
$parent = $target.closest(CLASS_PARENT);
|
||||||
|
|
||||||
|
$parent.find(CLASS_SELECT_TRIGGER).trigger('click');
|
||||||
|
},
|
||||||
|
|
||||||
|
openBottomSheets: function(e) {
|
||||||
|
var $this = $(e.target),
|
||||||
|
data = $this.data();
|
||||||
|
|
||||||
|
this.BottomSheets = $body.data('qor.bottomsheets');
|
||||||
|
this.$parent = $this.closest(CLASS_PARENT);
|
||||||
|
|
||||||
|
data.url = data.selectoneUrl;
|
||||||
|
|
||||||
|
this.SELECT_ONE_SELECTED_ICON = $('[name="select-one-selected-icon"]').html();
|
||||||
|
this.BottomSheets.open(data, this.handleSelectOne.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
initItem: function() {
|
||||||
|
var $selectFeild = this.$parent.find(CLASS_SELECT_FIELD),
|
||||||
|
selectedID;
|
||||||
|
|
||||||
|
if (!$selectFeild.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedID = $selectFeild.data().primaryKey;
|
||||||
|
|
||||||
|
if (selectedID) {
|
||||||
|
this.$bottomsheets
|
||||||
|
.find('tr[data-primary-key="' + selectedID + '"]')
|
||||||
|
.addClass(CLASS_SELECTED)
|
||||||
|
.find('td:first')
|
||||||
|
.append(this.SELECT_ONE_SELECTED_ICON);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
reloadData: function() {
|
||||||
|
this.initItem();
|
||||||
|
},
|
||||||
|
|
||||||
|
renderSelectOne: function(data) {
|
||||||
|
return Mustache.render($('[name="select-one-selected-template"]').html(), data);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleSelectOne: function($bottomsheets) {
|
||||||
|
var options = {
|
||||||
|
onSelect: this.onSelectResults.bind(this), //render selected item after click item lists
|
||||||
|
onSubmit: this.onSubmitResults.bind(this) //render new items after new item form submitted
|
||||||
|
};
|
||||||
|
|
||||||
|
$bottomsheets.qorSelectCore(options).addClass(CLASS_ONE);
|
||||||
|
this.$bottomsheets = $bottomsheets;
|
||||||
|
this.initItem();
|
||||||
|
},
|
||||||
|
|
||||||
|
onSelectResults: function(data) {
|
||||||
|
this.handleResults(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
onSubmitResults: function(data) {
|
||||||
|
this.handleResults(data, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleResults: function(data) {
|
||||||
|
var template,
|
||||||
|
$parent = this.$parent,
|
||||||
|
$select = $parent.find('select'),
|
||||||
|
$selectFeild = $parent.find(CLASS_SELECT_FIELD);
|
||||||
|
|
||||||
|
data.displayName = data.Text || data.Name || data.Title || data.Code || data[Object.keys(data)[0]];
|
||||||
|
data.selectoneValue = data.primaryKey || data.ID;
|
||||||
|
|
||||||
|
data.displayName = (data.displayName).escapeSymbol();
|
||||||
|
|
||||||
|
if (!$select.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template = this.renderSelectOne(data);
|
||||||
|
|
||||||
|
if ($selectFeild.length) {
|
||||||
|
$selectFeild.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent.prepend(template);
|
||||||
|
$parent.find(CLASS_SELECT_TRIGGER).hide();
|
||||||
|
|
||||||
|
$select.html(Mustache.render(QorSelectOne.SELECT_ONE_OPTION_TEMPLATE, data));
|
||||||
|
$select[0].value = data.primaryKey || data.ID;
|
||||||
|
|
||||||
|
$parent.trigger('qor.selectone.selected', [data]);
|
||||||
|
|
||||||
|
this.$bottomsheets.qorSelectCore('destroy').remove();
|
||||||
|
if (!$('.qor-bottomsheets').is(':visible')) {
|
||||||
|
$('body').removeClass('qor-bottomsheets-open');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSelectOne.SELECT_ONE_OPTION_TEMPLATE = '<option value="[[ selectoneValue ]]" selected>[[ displayName ]]</option>';
|
||||||
|
|
||||||
|
QorSelectOne.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorSelectOne(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = '[data-toggle="qor.selectone"]';
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorSelectOne.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorSelectOne.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorSelectOne;
|
||||||
|
});
|
||||||
274
app/views/qor/assets/javascripts/qor/qor-selector.js
Normal file
274
app/views/qor/assets/javascripts/qor/qor-selector.js
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var $document = $(document);
|
||||||
|
var NAMESPACE = 'qor.selector';
|
||||||
|
var EVENT_ENABLE = 'enable.' + NAMESPACE;
|
||||||
|
var EVENT_DISABLE = 'disable.' + NAMESPACE;
|
||||||
|
var EVENT_CLICK = 'click.' + NAMESPACE;
|
||||||
|
var EVENT_SELECTOR_CHANGE = 'selectorChanged.' + NAMESPACE;
|
||||||
|
var CLASS_OPEN = 'open';
|
||||||
|
var CLASS_ACTIVE = 'active';
|
||||||
|
var CLASS_HOVER = 'hover';
|
||||||
|
var CLASS_SELECTED = 'selected';
|
||||||
|
var CLASS_DISABLED = 'disabled';
|
||||||
|
var CLASS_CLEARABLE = 'clearable';
|
||||||
|
var SELECTOR_SELECTED = '.' + CLASS_SELECTED;
|
||||||
|
var SELECTOR_TOGGLE = '.qor-selector-toggle';
|
||||||
|
var SELECTOR_LABEL = '.qor-selector-label';
|
||||||
|
var SELECTOR_CLEAR = '.qor-selector-clear';
|
||||||
|
var SELECTOR_MENU = '.qor-selector-menu';
|
||||||
|
var CLASS_BOTTOMSHEETS = '.qor-bottomsheets';
|
||||||
|
|
||||||
|
function QorSelector(element, options) {
|
||||||
|
this.options = options;
|
||||||
|
this.$element = $(element);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorSelector.prototype = {
|
||||||
|
constructor: QorSelector,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
var $this = this.$element;
|
||||||
|
|
||||||
|
this.placeholder = $this.attr('placeholder') || $this.attr('name') || 'Select';
|
||||||
|
this.build();
|
||||||
|
},
|
||||||
|
|
||||||
|
build: function() {
|
||||||
|
var $this = this.$element;
|
||||||
|
var $selector = $(QorSelector.TEMPLATE);
|
||||||
|
var alignedClass = this.options.aligned + '-aligned';
|
||||||
|
var data = {};
|
||||||
|
var eleData = $this.data();
|
||||||
|
var hover = eleData.hover;
|
||||||
|
var paramName = $this.attr('name');
|
||||||
|
|
||||||
|
this.isBottom = eleData.position == 'bottom';
|
||||||
|
|
||||||
|
hover && $selector.addClass(CLASS_HOVER);
|
||||||
|
|
||||||
|
$selector
|
||||||
|
.addClass(alignedClass)
|
||||||
|
.find(SELECTOR_MENU)
|
||||||
|
.html(function() {
|
||||||
|
var list = [];
|
||||||
|
|
||||||
|
$this.children().each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var selected = $this.attr('selected');
|
||||||
|
var disabled = $this.attr('disabled');
|
||||||
|
var value = $this.attr('value');
|
||||||
|
var label = $this.text();
|
||||||
|
var classNames = [];
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
classNames.push(CLASS_SELECTED);
|
||||||
|
data.value = value;
|
||||||
|
data.label = label;
|
||||||
|
data.paramName = paramName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disabled) {
|
||||||
|
classNames.push(CLASS_DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
list.push(
|
||||||
|
'<li' +
|
||||||
|
(classNames.length ? ' class="' + classNames.join(' ') + '"' : '') +
|
||||||
|
' data-value="' +
|
||||||
|
value +
|
||||||
|
'"' +
|
||||||
|
' data-label="' +
|
||||||
|
label +
|
||||||
|
'"' +
|
||||||
|
' data-param-name="' +
|
||||||
|
paramName +
|
||||||
|
'"' +
|
||||||
|
'>' +
|
||||||
|
label +
|
||||||
|
'</li>'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return list.join('');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$selector = $selector;
|
||||||
|
$this.hide().after($selector);
|
||||||
|
$selector.find(SELECTOR_TOGGLE).data('paramName', paramName);
|
||||||
|
this.pick(data, true);
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
unbuild: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$selector.remove();
|
||||||
|
this.$element.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$selector.on(EVENT_CLICK, $.proxy(this.click, this));
|
||||||
|
$document.on(EVENT_CLICK, $.proxy(this.close, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$selector.off(EVENT_CLICK, this.click);
|
||||||
|
},
|
||||||
|
|
||||||
|
click: function(e) {
|
||||||
|
var $target = $(e.target);
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if ($target.is(SELECTOR_CLEAR)) {
|
||||||
|
this.clear();
|
||||||
|
} else if ($target.is('li')) {
|
||||||
|
if (!$target.hasClass(CLASS_SELECTED) && !$target.hasClass(CLASS_DISABLED)) {
|
||||||
|
this.pick($target.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.close();
|
||||||
|
} else if ($target.closest(SELECTOR_TOGGLE).length) {
|
||||||
|
this.open();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
pick: function(data, initialized) {
|
||||||
|
var $selector = this.$selector;
|
||||||
|
var selected = !!data.value;
|
||||||
|
var $element = this.$element;
|
||||||
|
|
||||||
|
$selector
|
||||||
|
.find(SELECTOR_TOGGLE)
|
||||||
|
.toggleClass(CLASS_ACTIVE, selected)
|
||||||
|
.toggleClass(CLASS_CLEARABLE, selected && this.options.clearable)
|
||||||
|
.find(SELECTOR_LABEL)
|
||||||
|
.text(data.label || this.placeholder);
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
$selector
|
||||||
|
.find(SELECTOR_MENU)
|
||||||
|
.children('[data-value="' + data.value + '"]')
|
||||||
|
.addClass(CLASS_SELECTED)
|
||||||
|
.siblings(SELECTOR_SELECTED)
|
||||||
|
.removeClass(CLASS_SELECTED);
|
||||||
|
|
||||||
|
$element.val(data.value);
|
||||||
|
|
||||||
|
if ($element.closest(CLASS_BOTTOMSHEETS).length && !$element.closest('[data-toggle="qor.filter"]').length) {
|
||||||
|
// If action is in bottom sheet, will trigger filterChanged.qor.selector event, add passed data.value parameter to event.
|
||||||
|
$(CLASS_BOTTOMSHEETS).trigger(EVENT_SELECTOR_CHANGE, [data.value, data.paramName]);
|
||||||
|
} else {
|
||||||
|
$element.trigger('change');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clear: function() {
|
||||||
|
var $element = this.$element;
|
||||||
|
|
||||||
|
this.$selector
|
||||||
|
.find(SELECTOR_TOGGLE)
|
||||||
|
.removeClass(CLASS_ACTIVE)
|
||||||
|
.removeClass(CLASS_CLEARABLE)
|
||||||
|
.find(SELECTOR_LABEL)
|
||||||
|
.text(this.placeholder)
|
||||||
|
.end()
|
||||||
|
.end()
|
||||||
|
.find(SELECTOR_MENU)
|
||||||
|
.children(SELECTOR_SELECTED)
|
||||||
|
.removeClass(CLASS_SELECTED);
|
||||||
|
|
||||||
|
$element.val('').trigger('change');
|
||||||
|
},
|
||||||
|
|
||||||
|
open: function() {
|
||||||
|
// Close other opened dropdowns first
|
||||||
|
$document.triggerHandler(EVENT_CLICK);
|
||||||
|
$('.qor-filter__dropdown').hide();
|
||||||
|
|
||||||
|
// Open the current dropdown
|
||||||
|
this.$selector.addClass(CLASS_OPEN);
|
||||||
|
if (this.isBottom) {
|
||||||
|
this.$selector.addClass('bottom');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
close: function() {
|
||||||
|
this.$selector.removeClass(CLASS_OPEN);
|
||||||
|
if (this.isBottom) {
|
||||||
|
this.$selector.removeClass('bottom');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbuild();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSelector.DEFAULTS = {
|
||||||
|
aligned: 'left',
|
||||||
|
clearable: false
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSelector.TEMPLATE =
|
||||||
|
'<div class="qor-selector">' +
|
||||||
|
'<a class="qor-selector-toggle">' +
|
||||||
|
'<span class="qor-selector-label"></span>' +
|
||||||
|
'<i class="material-icons qor-selector-arrow">arrow_drop_down</i>' +
|
||||||
|
'<i class="material-icons qor-selector-clear">clear</i>' +
|
||||||
|
'</a>' +
|
||||||
|
'<ul class="qor-selector-menu"></ul>' +
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
QorSelector.plugin = function(option) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var options;
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
options = $.extend({}, QorSelector.DEFAULTS, $this.data(), typeof option === 'object' && option);
|
||||||
|
$this.data(NAMESPACE, (data = new QorSelector(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof option === 'string' && $.isFunction((fn = data[option]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = '[data-toggle="qor.selector"]';
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorSelector.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorSelector.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorSelector;
|
||||||
|
});
|
||||||
689
app/views/qor/assets/javascripts/qor/qor-slideout.js
Normal file
689
app/views/qor/assets/javascripts/qor/qor-slideout.js
Normal file
@@ -0,0 +1,689 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === "function" && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(["jquery"], factory);
|
||||||
|
} else if (typeof exports === "object") {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require("jquery"));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let $document = $(document),
|
||||||
|
FormData = window.FormData,
|
||||||
|
QOR_Translations = window.QOR_Translations,
|
||||||
|
_ = window._,
|
||||||
|
QOR = window.QOR,
|
||||||
|
NAMESPACE = "qor.slideout",
|
||||||
|
EVENT_KEYUP = "keyup." + NAMESPACE,
|
||||||
|
EVENT_CLICK = "click." + NAMESPACE,
|
||||||
|
EVENT_SUBMIT = "submit." + NAMESPACE,
|
||||||
|
EVENT_SHOW = "show." + NAMESPACE,
|
||||||
|
EVENT_SLIDEOUT_SUBMIT_COMPLEMENT = "slideoutSubmitComplete." + NAMESPACE,
|
||||||
|
EVENT_SLIDEOUT_CLOSED = "slideoutClosed." + NAMESPACE,
|
||||||
|
EVENT_SLIDEOUT_LOADED = "slideoutLoaded." + NAMESPACE,
|
||||||
|
EVENT_SLIDEOUT_BEFORESEND = "slideoutBeforeSend." + NAMESPACE,
|
||||||
|
EVENT_SHOWN = "shown." + NAMESPACE,
|
||||||
|
EVENT_HIDE = "hide." + NAMESPACE,
|
||||||
|
EVENT_HIDDEN = "hidden." + NAMESPACE,
|
||||||
|
EVENT_TRANSITIONEND = "transitionend",
|
||||||
|
CLASS_OPEN = "qor-slideout-open",
|
||||||
|
CLASS_MINI = "qor-slideout-mini",
|
||||||
|
CLASS_IS_SHOWN = "is-shown",
|
||||||
|
CLASS_IS_SLIDED = "is-slided",
|
||||||
|
CLASS_IS_SELECTED = "is-selected",
|
||||||
|
CLASS_MAIN_CONTENT = ".mdl-layout__content.qor-page",
|
||||||
|
CLASS_HEADER_LOCALE = ".qor-actions__locale",
|
||||||
|
CLASS_BODY_LOADING = ".qor-body__loading";
|
||||||
|
|
||||||
|
function replaceHtml(el, html) {
|
||||||
|
let oldEl = typeof el === "string" ? document.getElementById(el) : el,
|
||||||
|
newEl = oldEl.cloneNode(false);
|
||||||
|
newEl.innerHTML = html;
|
||||||
|
oldEl.parentNode.replaceChild(newEl, oldEl);
|
||||||
|
return newEl;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushArrary($ele, isScript) {
|
||||||
|
let array = [],
|
||||||
|
prop = "href";
|
||||||
|
|
||||||
|
isScript && (prop = "src");
|
||||||
|
$ele.each(function() {
|
||||||
|
array.push($(this).attr(prop));
|
||||||
|
});
|
||||||
|
return _.uniq(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
function execSlideoutEvents(url, response) {
|
||||||
|
// exec qorSliderAfterShow after script loaded
|
||||||
|
var qorSliderAfterShow = $.fn.qorSliderAfterShow;
|
||||||
|
for (var name in qorSliderAfterShow) {
|
||||||
|
if (
|
||||||
|
qorSliderAfterShow.hasOwnProperty(name) &&
|
||||||
|
!qorSliderAfterShow[name]["isLoaded"]
|
||||||
|
) {
|
||||||
|
qorSliderAfterShow[name]["isLoaded"] = true;
|
||||||
|
qorSliderAfterShow[name].call(this, url, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadScripts(srcs, data, callback) {
|
||||||
|
let scriptsLoaded = 0;
|
||||||
|
|
||||||
|
for (let i = 0, len = srcs.length; i < len; i++) {
|
||||||
|
let script = document.createElement("script");
|
||||||
|
|
||||||
|
script.onload = function() {
|
||||||
|
scriptsLoaded++;
|
||||||
|
|
||||||
|
if (scriptsLoaded === srcs.length) {
|
||||||
|
if ($.isFunction(callback)) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data && data.url && data.response) {
|
||||||
|
execSlideoutEvents(data.url, data.response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
script.src = srcs[i];
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadStyles(srcs) {
|
||||||
|
let ss = document.createElement("link"),
|
||||||
|
src = srcs.shift();
|
||||||
|
|
||||||
|
ss.type = "text/css";
|
||||||
|
ss.rel = "stylesheet";
|
||||||
|
ss.onload = function() {
|
||||||
|
if (srcs.length) {
|
||||||
|
loadStyles(srcs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ss.href = src;
|
||||||
|
document.getElementsByTagName("head")[0].appendChild(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareScripts($scripts) {
|
||||||
|
let $currentPageScripts = $("script"),
|
||||||
|
slideoutScripts = pushArrary($scripts, true),
|
||||||
|
currentPageScripts = pushArrary($currentPageScripts, true),
|
||||||
|
scriptDiff = _.difference(slideoutScripts, currentPageScripts);
|
||||||
|
return scriptDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareLinks($links) {
|
||||||
|
let $currentStyles = $("link"),
|
||||||
|
slideoutStyles = pushArrary($links),
|
||||||
|
currentStyles = pushArrary($currentStyles),
|
||||||
|
styleDiff = _.difference(slideoutStyles, currentStyles);
|
||||||
|
|
||||||
|
return styleDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function QorSlideout(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend(
|
||||||
|
{},
|
||||||
|
QorSlideout.DEFAULTS,
|
||||||
|
$.isPlainObject(options) && options
|
||||||
|
);
|
||||||
|
this.slided = false;
|
||||||
|
this.disabled = false;
|
||||||
|
this.slideoutType = false;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorSlideout.prototype = {
|
||||||
|
constructor: QorSlideout,
|
||||||
|
|
||||||
|
init: function() {
|
||||||
|
this.build();
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
build: function() {
|
||||||
|
var $slideout;
|
||||||
|
|
||||||
|
this.$slideout = $slideout = $(QorSlideout.TEMPLATE).appendTo("body");
|
||||||
|
this.$slideoutTemplate = $slideout.html();
|
||||||
|
},
|
||||||
|
|
||||||
|
unbuild: function() {
|
||||||
|
this.$slideout.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
this.$slideout
|
||||||
|
.on(EVENT_SUBMIT, "form", this.submit.bind(this))
|
||||||
|
.on(
|
||||||
|
EVENT_CLICK,
|
||||||
|
".qor-slideout__fullscreen",
|
||||||
|
this.toggleSlideoutMode.bind(this)
|
||||||
|
)
|
||||||
|
.on(EVENT_CLICK, '[data-dismiss="slideout"]', this.hide.bind(this));
|
||||||
|
|
||||||
|
$document.on(EVENT_KEYUP, $.proxy(this.keyup, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$slideout.off(EVENT_SUBMIT, this.submit).off(EVENT_CLICK);
|
||||||
|
|
||||||
|
$document.off(EVENT_KEYUP, this.keyup);
|
||||||
|
},
|
||||||
|
|
||||||
|
keyup: function(e) {
|
||||||
|
if (e.which === 27) {
|
||||||
|
if (
|
||||||
|
$(".qor-bottomsheets").is(":visible") ||
|
||||||
|
$(".qor-modal").is(":visible") ||
|
||||||
|
$("#redactor-modal-box").length ||
|
||||||
|
$("#dialog").is(":visible")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hide();
|
||||||
|
this.removeSelectedClass();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
loadExtraResource: function(data) {
|
||||||
|
let styleDiff = compareLinks(data.$links),
|
||||||
|
scriptDiff = compareScripts(data.$scripts);
|
||||||
|
|
||||||
|
if (styleDiff.length) {
|
||||||
|
loadStyles(styleDiff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scriptDiff.length) {
|
||||||
|
loadScripts(scriptDiff, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
removeSelectedClass: function() {
|
||||||
|
this.$element.find("[data-url]").removeClass(CLASS_IS_SELECTED);
|
||||||
|
},
|
||||||
|
|
||||||
|
addLoading: function() {
|
||||||
|
$(CLASS_BODY_LOADING).remove();
|
||||||
|
var $loading = $(QorSlideout.TEMPLATE_LOADING);
|
||||||
|
$loading.appendTo($("body")).trigger("enable.qor.material");
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleSlideoutMode: function() {
|
||||||
|
this.$slideout
|
||||||
|
.toggleClass("qor-slideout__fullscreen")
|
||||||
|
.find(".qor-slideout__fullscreen i")
|
||||||
|
.toggle();
|
||||||
|
},
|
||||||
|
|
||||||
|
checkRichedutorHTMLTags: function(source){
|
||||||
|
var DOMHolderArray = new Array();
|
||||||
|
var tagsArray = new Array();
|
||||||
|
var lines = source.value.split('\n');
|
||||||
|
for (var x = 0; x < lines.length; x++) {
|
||||||
|
tagsArray = lines[x].match(/<(\/{1})?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)>/g);
|
||||||
|
if (tagsArray) {
|
||||||
|
for (var i = 0; i < tagsArray.length; i++) {
|
||||||
|
if (tagsArray[i].indexOf('</') >= 0) {
|
||||||
|
let elementToPop = tagsArray[i].substr(2, tagsArray[i].length - 3);
|
||||||
|
elementToPop = elementToPop.replace(/ /g, '');
|
||||||
|
for (var j = DOMHolderArray.length - 1; j >= 0; j--) {
|
||||||
|
if (DOMHolderArray[j].element == elementToPop) {
|
||||||
|
DOMHolderArray.splice(j, 1);
|
||||||
|
if (elementToPop != 'html') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var tag = new Object();
|
||||||
|
tag.full = tagsArray[i];
|
||||||
|
tag.line = x + 1;
|
||||||
|
if (tag.full.indexOf(' ') > 0) {
|
||||||
|
tag.element = tag.full.substr(1, tag.full.indexOf(' ') - 1);
|
||||||
|
} else {
|
||||||
|
tag.element = tag.full.substr(1, tag.full.length - 2);
|
||||||
|
}
|
||||||
|
var selfClosingTags = new Array('area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr');
|
||||||
|
var isSelfClosing = false;
|
||||||
|
for (var y = 0; y < selfClosingTags.length; y++) {
|
||||||
|
if (selfClosingTags[y].localeCompare(tag.element) == 0) {
|
||||||
|
isSelfClosing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isSelfClosing == false) {
|
||||||
|
DOMHolderArray.push(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DOMHolderArray.length;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
submit: function(e) {
|
||||||
|
let $slideout = this.$slideout,
|
||||||
|
form = e.target,
|
||||||
|
$form = $(form),
|
||||||
|
_this = this,
|
||||||
|
$loading = $(QOR.$formLoading),
|
||||||
|
$submit = $form.find(":submit"),
|
||||||
|
hasNotClosedTags = false;
|
||||||
|
|
||||||
|
if ($form.data("normal-submit")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$slideout.trigger(EVENT_SLIDEOUT_BEFORESEND);
|
||||||
|
|
||||||
|
if (!FormData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
document.querySelectorAll('.qor-redactor-box .redactor-source').forEach(function(item) {
|
||||||
|
if(_this.checkRichedutorHTMLTags(item)){
|
||||||
|
hasNotClosedTags=true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(hasNotClosedTags){
|
||||||
|
QOR.qorConfirm(QOR_Translations.slideoutCheckHTMLTagsError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.submitXHR = $.ajax($form.prop("action"), {
|
||||||
|
method: $form.prop("method"),
|
||||||
|
data: new FormData(form),
|
||||||
|
dataType: "html",
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
beforeSend: function() {
|
||||||
|
$(".qor-submit-loading").remove();
|
||||||
|
$loading
|
||||||
|
.appendTo(
|
||||||
|
$submit.prop("disabled", true).closest(".qor-form__actions")
|
||||||
|
)
|
||||||
|
.trigger("enable.qor.material");
|
||||||
|
$.fn.qorSlideoutBeforeHide = null;
|
||||||
|
},
|
||||||
|
success: function() {
|
||||||
|
let returnUrl = $form.data("returnUrl"),
|
||||||
|
refreshUrl = $form.data("refreshUrl");
|
||||||
|
|
||||||
|
$slideout.trigger(EVENT_SLIDEOUT_SUBMIT_COMPLEMENT);
|
||||||
|
|
||||||
|
if (refreshUrl) {
|
||||||
|
window.location.href = refreshUrl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnUrl == "refresh") {
|
||||||
|
_this.refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnUrl && returnUrl != "refresh") {
|
||||||
|
_this.load(returnUrl);
|
||||||
|
} else {
|
||||||
|
_this.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(err) {
|
||||||
|
QOR.handleAjaxError(err);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
$submit.prop("disabled", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
load: function(url, data) {
|
||||||
|
var options = this.options;
|
||||||
|
var method;
|
||||||
|
var dataType;
|
||||||
|
var load;
|
||||||
|
var $slideout = this.$slideout;
|
||||||
|
var $title;
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = $.isPlainObject(data) ? data : {};
|
||||||
|
|
||||||
|
method = data.method ? data.method : "GET";
|
||||||
|
dataType = data.datatype ? data.datatype : "html";
|
||||||
|
|
||||||
|
load = $.proxy(function() {
|
||||||
|
$.ajax(url, {
|
||||||
|
method: method,
|
||||||
|
dataType: dataType,
|
||||||
|
cache: true,
|
||||||
|
ifModified: true,
|
||||||
|
success: $.proxy(function(response) {
|
||||||
|
let $response,
|
||||||
|
$content,
|
||||||
|
$qorFormContainer,
|
||||||
|
$scripts,
|
||||||
|
$links,
|
||||||
|
bodyClass;
|
||||||
|
|
||||||
|
$(CLASS_BODY_LOADING).remove();
|
||||||
|
|
||||||
|
if (method === "GET") {
|
||||||
|
$response = $(response);
|
||||||
|
$content = $response.find(CLASS_MAIN_CONTENT);
|
||||||
|
$qorFormContainer = $content.find(".qor-form-container");
|
||||||
|
this.slideoutType =
|
||||||
|
$qorFormContainer.length &&
|
||||||
|
$qorFormContainer.data().slideoutType;
|
||||||
|
|
||||||
|
if (!$content.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bodyHtml = response.match(
|
||||||
|
/<\s*body.*>[\s\S]*<\s*\/body\s*>/gi
|
||||||
|
);
|
||||||
|
if (bodyHtml) {
|
||||||
|
bodyHtml = bodyHtml
|
||||||
|
.join("")
|
||||||
|
.replace(/<\s*body/gi, "<div")
|
||||||
|
.replace(/<\s*\/body/gi, "</div");
|
||||||
|
bodyClass = $(bodyHtml).prop("class");
|
||||||
|
$("body").addClass(bodyClass);
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
$scripts: $response.filter("script"),
|
||||||
|
$links: $response.filter("link"),
|
||||||
|
url: url,
|
||||||
|
response: response
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadExtraResource(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content
|
||||||
|
.find(".qor-button--cancel")
|
||||||
|
.attr("data-dismiss", "slideout")
|
||||||
|
.removeAttr("href");
|
||||||
|
|
||||||
|
$scripts = compareScripts($content.find("script[src]"));
|
||||||
|
$links = compareLinks($content.find("link[href]"));
|
||||||
|
|
||||||
|
if ($scripts.length) {
|
||||||
|
let data = {
|
||||||
|
url: url,
|
||||||
|
response: response
|
||||||
|
};
|
||||||
|
|
||||||
|
loadScripts($scripts, data, function() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($links.length) {
|
||||||
|
loadStyles($links);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content.find("script[src],link[href]").remove();
|
||||||
|
|
||||||
|
// reset slideout header and body
|
||||||
|
$slideout.html(this.$slideoutTemplate);
|
||||||
|
$title = $slideout.find(".qor-slideout__title");
|
||||||
|
this.$body = $slideout.find(".qor-slideout__body");
|
||||||
|
|
||||||
|
$title.html($response.find(options.title).html());
|
||||||
|
replaceHtml(
|
||||||
|
$slideout.find(".qor-slideout__body")[0],
|
||||||
|
$content.html()
|
||||||
|
);
|
||||||
|
this.$body.find(CLASS_HEADER_LOCALE).remove();
|
||||||
|
|
||||||
|
$slideout
|
||||||
|
.one(EVENT_SHOWN, function() {
|
||||||
|
$(this).trigger("enable");
|
||||||
|
})
|
||||||
|
.one(EVENT_HIDDEN, function() {
|
||||||
|
$(this).trigger("disable");
|
||||||
|
});
|
||||||
|
|
||||||
|
$slideout.find(".qor-slideout__opennew").attr("href", url);
|
||||||
|
this.show();
|
||||||
|
|
||||||
|
// callback for after slider loaded HTML
|
||||||
|
// this callback is deprecated, use slideoutLoaded.qor.slideout event.
|
||||||
|
var qorSliderAfterShow = $.fn.qorSliderAfterShow;
|
||||||
|
if (qorSliderAfterShow) {
|
||||||
|
for (var name in qorSliderAfterShow) {
|
||||||
|
if (
|
||||||
|
qorSliderAfterShow.hasOwnProperty(name) &&
|
||||||
|
$.isFunction(qorSliderAfterShow[name])
|
||||||
|
) {
|
||||||
|
qorSliderAfterShow[name]["isLoaded"] = true;
|
||||||
|
qorSliderAfterShow[name].call(this, url, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// will trigger slideoutLoaded.qor.slideout event after slideout loaded
|
||||||
|
$slideout.trigger(EVENT_SLIDEOUT_LOADED, [url, response]);
|
||||||
|
} else {
|
||||||
|
if (data.returnUrl) {
|
||||||
|
this.load(data.returnUrl);
|
||||||
|
} else {
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, this),
|
||||||
|
|
||||||
|
error: $.proxy(function() {
|
||||||
|
var errors;
|
||||||
|
$(CLASS_BODY_LOADING).remove();
|
||||||
|
if ($(".qor-error span").length > 0) {
|
||||||
|
errors = $(".qor-error span")
|
||||||
|
.map(function() {
|
||||||
|
return $(this).text();
|
||||||
|
})
|
||||||
|
.get()
|
||||||
|
.join(", ");
|
||||||
|
} else {
|
||||||
|
errors = QOR_Translations.serverError;
|
||||||
|
}
|
||||||
|
window.alert(errors);
|
||||||
|
}, this)
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
if (this.slided) {
|
||||||
|
this.hide(true);
|
||||||
|
this.$slideout.one(EVENT_HIDDEN, load);
|
||||||
|
} else {
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
open: function(options) {
|
||||||
|
this.addLoading();
|
||||||
|
this.load(options.url, options.data);
|
||||||
|
},
|
||||||
|
|
||||||
|
reload: function(url) {
|
||||||
|
this.hide();
|
||||||
|
this.load(url);
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function() {
|
||||||
|
var $slideout = this.$slideout;
|
||||||
|
var showEvent;
|
||||||
|
|
||||||
|
if (this.slided) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showEvent = $.Event(EVENT_SHOW);
|
||||||
|
$slideout.trigger(showEvent);
|
||||||
|
|
||||||
|
if (showEvent.isDefaultPrevented()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$slideout.removeClass(CLASS_MINI);
|
||||||
|
this.slideoutType == "mini" && $slideout.addClass(CLASS_MINI);
|
||||||
|
|
||||||
|
$slideout.addClass(CLASS_IS_SHOWN).get(0).offsetWidth;
|
||||||
|
$slideout
|
||||||
|
.one(EVENT_TRANSITIONEND, $.proxy(this.shown, this))
|
||||||
|
.addClass(CLASS_IS_SLIDED)
|
||||||
|
.scrollTop(0);
|
||||||
|
},
|
||||||
|
|
||||||
|
shown: function() {
|
||||||
|
this.slided = true;
|
||||||
|
// Disable to scroll body element
|
||||||
|
$("body").addClass(CLASS_OPEN);
|
||||||
|
this.$slideout
|
||||||
|
.trigger("beforeEnable.qor.slideout")
|
||||||
|
.trigger(EVENT_SHOWN)
|
||||||
|
.trigger("afterEnable.qor.slideout");
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function() {
|
||||||
|
let message = {
|
||||||
|
confirm: QOR_Translations.slideoutCloseWarning
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($.fn.qorSlideoutBeforeHide) {
|
||||||
|
QOR.qorConfirm(
|
||||||
|
message,
|
||||||
|
function(confirm) {
|
||||||
|
if (confirm) {
|
||||||
|
this.hideSlideout();
|
||||||
|
}
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.hideSlideout();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeSelectedClass();
|
||||||
|
},
|
||||||
|
|
||||||
|
hideSlideout: function() {
|
||||||
|
var $slideout = this.$slideout;
|
||||||
|
var hideEvent;
|
||||||
|
var $datePicker = $(".qor-datepicker").not(".hidden");
|
||||||
|
|
||||||
|
// remove onbeforeunload event
|
||||||
|
window.onbeforeunload = null;
|
||||||
|
$.fn.qorSlideoutBeforeHide = null;
|
||||||
|
|
||||||
|
this.submitXHR && this.submitXHR.abort();
|
||||||
|
|
||||||
|
if ($datePicker.length) {
|
||||||
|
$datePicker.addClass("hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.slided) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideEvent = $.Event(EVENT_HIDE);
|
||||||
|
$slideout.trigger(hideEvent);
|
||||||
|
|
||||||
|
if (hideEvent.isDefaultPrevented()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$slideout
|
||||||
|
.one(EVENT_TRANSITIONEND, $.proxy(this.hidden, this))
|
||||||
|
.removeClass(`${CLASS_IS_SLIDED} qor-slideout__fullscreen`);
|
||||||
|
$slideout.trigger(EVENT_SLIDEOUT_CLOSED);
|
||||||
|
},
|
||||||
|
|
||||||
|
hidden: function() {
|
||||||
|
this.slided = false;
|
||||||
|
|
||||||
|
// Enable to scroll body element
|
||||||
|
$("body").removeClass(CLASS_OPEN);
|
||||||
|
|
||||||
|
this.$slideout.removeClass(CLASS_IS_SHOWN).trigger(EVENT_HIDDEN);
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh: function() {
|
||||||
|
this.hide();
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
window.location.reload();
|
||||||
|
}, 350);
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.unbuild();
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSlideout.DEFAULTS = {
|
||||||
|
title: ".qor-form-title, .mdl-layout-title",
|
||||||
|
content: false
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSlideout.TEMPLATE = `<div class="qor-slideout">
|
||||||
|
<div class="qor-slideout__header">
|
||||||
|
<div class="qor-slideout__header-link">
|
||||||
|
<a href="#" target="_blank" class="mdl-button mdl-button--icon mdl-js-button mdl-js-repple-effect qor-slideout__opennew"><i class="material-icons">open_in_new</i></a>
|
||||||
|
<a href="#" class="mdl-button mdl-button--icon mdl-js-button mdl-js-repple-effect qor-slideout__fullscreen">
|
||||||
|
<i class="material-icons">fullscreen</i>
|
||||||
|
<i class="material-icons" style="display: none;">fullscreen_exit</i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="mdl-button mdl-button--icon mdl-js-button mdl-js-repple-effect qor-slideout__close" data-dismiss="slideout">
|
||||||
|
<span class="material-icons">close</span>
|
||||||
|
</button>
|
||||||
|
<h3 class="qor-slideout__title"></h3>
|
||||||
|
</div>
|
||||||
|
<div class="qor-slideout__body"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorSlideout.TEMPLATE_LOADING = `<div class="qor-body__loading">
|
||||||
|
<div><div class="mdl-spinner mdl-js-spinner is-active qor-layout__bottomsheet-spinner"></div></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
QorSlideout.plugin = function(options) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorSlideout(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === "string" && $.isFunction((fn = data[options]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.qorSlideout = QorSlideout.plugin;
|
||||||
|
|
||||||
|
return QorSlideout;
|
||||||
|
});
|
||||||
110
app/views/qor/assets/javascripts/qor/qor-sorter.js
Normal file
110
app/views/qor/assets/javascripts/qor/qor-sorter.js
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
(function (factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function ($) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var location = window.location;
|
||||||
|
var NAMESPACE = 'qor.sorter';
|
||||||
|
var EVENT_ENABLE = 'enable.' + NAMESPACE;
|
||||||
|
var EVENT_DISABLE = 'disable.' + NAMESPACE;
|
||||||
|
var EVENT_CLICK = 'click.' + NAMESPACE;
|
||||||
|
var CLASS_IS_SORTABLE = 'is-sortable';
|
||||||
|
|
||||||
|
function QorSorter(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorSorter.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorSorter.prototype = {
|
||||||
|
constructor: QorSorter,
|
||||||
|
|
||||||
|
init: function () {
|
||||||
|
this.$element.addClass(CLASS_IS_SORTABLE);
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function () {
|
||||||
|
this.$element.on(EVENT_CLICK, '> thead > tr > th', $.proxy(this.sort, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function () {
|
||||||
|
this.$element.off(EVENT_CLICK, this.sort);
|
||||||
|
},
|
||||||
|
|
||||||
|
sort: function (e) {
|
||||||
|
var $target = $(e.currentTarget);
|
||||||
|
var orderBy = $target.data('orderBy');
|
||||||
|
var search = location.search;
|
||||||
|
var param = 'order_by=' + orderBy;
|
||||||
|
|
||||||
|
// Stop when it is not sortable
|
||||||
|
if (!orderBy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/order_by/.test(search)) {
|
||||||
|
search = search.replace(/order_by(=\w+)?/, function () {
|
||||||
|
return param;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
search += search.indexOf('?') > -1 ? ('&' + param) : param;
|
||||||
|
}
|
||||||
|
|
||||||
|
location.search = search;
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
this.unbind();
|
||||||
|
this.$element.removeClass(CLASS_IS_SORTABLE).removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorSorter.DEFAULTS = {};
|
||||||
|
|
||||||
|
QorSorter.plugin = function (options) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorSorter(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction(fn = data[options])) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
var selector = '.qor-js-table';
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function (e) {
|
||||||
|
QorSorter.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function (e) {
|
||||||
|
QorSorter.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorSorter;
|
||||||
|
|
||||||
|
});
|
||||||
210
app/views/qor/assets/javascripts/qor/qor-tabs.js
Normal file
210
app/views/qor/assets/javascripts/qor/qor-tabs.js
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
(function (factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function ($) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = window._;
|
||||||
|
var $body = $('body');
|
||||||
|
var NAMESPACE = 'qor.tabbar';
|
||||||
|
var EVENT_ENABLE = 'enable.' + NAMESPACE;
|
||||||
|
var EVENT_DISABLE = 'disable.' + NAMESPACE;
|
||||||
|
var EVENT_CLICK = 'click.' + NAMESPACE;
|
||||||
|
var CLASS_TAB = '.qor-layout__tab-button';
|
||||||
|
var CLASS_TAB_CONTENT = '.qor-layout__tab-content';
|
||||||
|
var CLASS_TAB_BAR = '.mdl-layout__tab-bar-container';
|
||||||
|
var CLASS_TAB_BAR_RIGHT = '.qor-layout__tab-right';
|
||||||
|
var CLASS_TAB_BAR_LEFT = '.qor-layout__tab-left';
|
||||||
|
var CLASS_ACTIVE = 'is-active';
|
||||||
|
|
||||||
|
function QorTab(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend({}, QorTab.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorTab.prototype = {
|
||||||
|
constructor: QorTab,
|
||||||
|
|
||||||
|
init: function () {
|
||||||
|
this.initTab();
|
||||||
|
this.bind();
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function () {
|
||||||
|
this.$element.on(EVENT_CLICK, CLASS_TAB, this.switchTab.bind(this));
|
||||||
|
this.$element.on(EVENT_CLICK, CLASS_TAB_BAR_RIGHT, this.scrollTabRight.bind(this));
|
||||||
|
this.$element.on(EVENT_CLICK, CLASS_TAB_BAR_LEFT, this.scrollTabLeft.bind(this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function () {
|
||||||
|
this.$element.off(EVENT_CLICK, CLASS_TAB, this.switchTab);
|
||||||
|
this.$element.off(EVENT_CLICK, CLASS_TAB_BAR_RIGHT, this.scrollTabRight);
|
||||||
|
this.$element.off(EVENT_CLICK, CLASS_TAB_BAR_LEFT, this.scrollTabLeft);
|
||||||
|
},
|
||||||
|
|
||||||
|
initTab: function () {
|
||||||
|
var data = this.$element.data();
|
||||||
|
|
||||||
|
if (!data.scopeActive) {
|
||||||
|
$(CLASS_TAB).first().addClass(CLASS_ACTIVE);
|
||||||
|
$body.data('tabScopeActive',$(CLASS_TAB).first().data('name'));
|
||||||
|
} else {
|
||||||
|
$body.data('tabScopeActive',data.scopeActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tabWidth = 0;
|
||||||
|
this.slideoutWidth = $(CLASS_TAB_CONTENT).outerWidth();
|
||||||
|
|
||||||
|
_.each($(CLASS_TAB), function(ele) {
|
||||||
|
this.tabWidth = this.tabWidth + $(ele).outerWidth();
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
if (this.tabWidth > this.slideoutWidth) {
|
||||||
|
this.$element.find(CLASS_TAB_BAR).append(QorTab.ARROW_RIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
scrollTabLeft: function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
var $scrollBar = $(CLASS_TAB_BAR),
|
||||||
|
scrollLeft = $scrollBar.scrollLeft(),
|
||||||
|
jumpDistance = scrollLeft - this.slideoutWidth;
|
||||||
|
|
||||||
|
if (scrollLeft > 0){
|
||||||
|
$scrollBar.animate({scrollLeft:jumpDistance}, 400, function () {
|
||||||
|
|
||||||
|
$(CLASS_TAB_BAR_RIGHT).show();
|
||||||
|
if ($scrollBar.scrollLeft() == 0) {
|
||||||
|
$(CLASS_TAB_BAR_LEFT).hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
scrollTabRight: function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
var $scrollBar = $(CLASS_TAB_BAR),
|
||||||
|
scrollLeft = $scrollBar.scrollLeft(),
|
||||||
|
tabWidth = this.tabWidth,
|
||||||
|
slideoutWidth = this.slideoutWidth,
|
||||||
|
jumpDistance = scrollLeft + slideoutWidth;
|
||||||
|
|
||||||
|
if (jumpDistance < tabWidth){
|
||||||
|
$scrollBar.animate({scrollLeft:jumpDistance}, 400, function () {
|
||||||
|
|
||||||
|
$(CLASS_TAB_BAR_LEFT).show();
|
||||||
|
if ($scrollBar.scrollLeft() + slideoutWidth >= tabWidth) {
|
||||||
|
$(CLASS_TAB_BAR_RIGHT).hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
!$(CLASS_TAB_BAR_LEFT).length && this.$element.find(CLASS_TAB_BAR).prepend(QorTab.ARROW_LEFT);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
switchTab: function (e) {
|
||||||
|
var $target = $(e.target),
|
||||||
|
$element = this.$element,
|
||||||
|
data = $target.data(),
|
||||||
|
tabScopeActive = $body.data().tabScopeActive,
|
||||||
|
isInSlideout = $('.qor-slideout').is(':visible');
|
||||||
|
|
||||||
|
if (!isInSlideout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target.hasClass(CLASS_ACTIVE)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$element.find(CLASS_TAB).removeClass(CLASS_ACTIVE);
|
||||||
|
$target.addClass(CLASS_ACTIVE);
|
||||||
|
|
||||||
|
$.ajax(data.tabUrl, {
|
||||||
|
method: 'GET',
|
||||||
|
dataType: 'html',
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
beforeSend: function () {
|
||||||
|
$('.qor-layout__tab-spinner').remove();
|
||||||
|
var $spinner = '<div class="mdl-spinner mdl-js-spinner is-active qor-layout__tab-spinner"></div>';
|
||||||
|
$(CLASS_TAB_CONTENT).hide().before($spinner);
|
||||||
|
window.componentHandler.upgradeElement($('.qor-layout__tab-spinner')[0]);
|
||||||
|
},
|
||||||
|
success: function (html) {
|
||||||
|
$('.qor-layout__tab-spinner').remove();
|
||||||
|
$body.data('tabScopeActive',$target.data('name'));
|
||||||
|
var $content = $(html).find(CLASS_TAB_CONTENT).html();
|
||||||
|
$(CLASS_TAB_CONTENT).show().html($content).trigger('enable');
|
||||||
|
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
$('.qor-layout__tab-spinner').remove();
|
||||||
|
$body.data('tabScopeActive',tabScopeActive);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
this.unbind();
|
||||||
|
$body.removeData('tabScopeActive');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorTab.ARROW_RIGHT = '<a href="javascript://" class="qor-layout__tab-right"></a>';
|
||||||
|
QorTab.ARROW_LEFT = '<a href="javascript://" class="qor-layout__tab-left"></a>';
|
||||||
|
|
||||||
|
QorTab.DEFAULTS = {};
|
||||||
|
|
||||||
|
QorTab.plugin = function (options) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (/destroy/.test(options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data(NAMESPACE, (data = new QorTab(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'string' && $.isFunction(fn = data[options])) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
var selector = '[data-toggle="qor.tab"]';
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function (e) {
|
||||||
|
QorTab.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function (e) {
|
||||||
|
QorTab.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorTab;
|
||||||
|
|
||||||
|
});
|
||||||
262
app/views/qor/assets/javascripts/qor/qor-timepicker.js
Normal file
262
app/views/qor/assets/javascripts/qor/qor-timepicker.js
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
(function(factory) {
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD. Register as anonymous module.
|
||||||
|
define(['jquery'], factory);
|
||||||
|
} else if (typeof exports === 'object') {
|
||||||
|
// Node / CommonJS
|
||||||
|
factory(require('jquery'));
|
||||||
|
} else {
|
||||||
|
// Browser globals.
|
||||||
|
factory(jQuery);
|
||||||
|
}
|
||||||
|
})(function($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var NAMESPACE = 'qor.timepicker';
|
||||||
|
var EVENT_ENABLE = 'enable.' + NAMESPACE;
|
||||||
|
var EVENT_DISABLE = 'disable.' + NAMESPACE;
|
||||||
|
var EVENT_CLICK = 'click.' + NAMESPACE;
|
||||||
|
var EVENT_FOCUS = 'focus.' + NAMESPACE;
|
||||||
|
var EVENT_KEYDOWN = 'keydown.' + NAMESPACE;
|
||||||
|
var EVENT_BLUR = 'blur.' + NAMESPACE;
|
||||||
|
var EVENT_CHANGE_TIME = 'selectTime.' + NAMESPACE;
|
||||||
|
|
||||||
|
var CLASS_PARENT = '[data-picker-type]';
|
||||||
|
var CLASS_TIME_SELECTED = '.ui-timepicker-selected';
|
||||||
|
|
||||||
|
function QorTimepicker(element, options) {
|
||||||
|
this.$element = $(element);
|
||||||
|
this.options = $.extend(true, {}, QorTimepicker.DEFAULTS, $.isPlainObject(options) && options);
|
||||||
|
this.formatDate = null;
|
||||||
|
this.pickerData = this.$element.data();
|
||||||
|
this.parent = this.$element.closest(CLASS_PARENT);
|
||||||
|
this.isDateTimePicker = this.parent.data('picker-type') == 'datetime';
|
||||||
|
this.$targetInput = this.parent.find(this.pickerData.targetInput || (this.isDateTimePicker ? '.qor-datetimepicker__input' : '.qor-datepicker__input'));
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
QorTimepicker.prototype = {
|
||||||
|
init: function() {
|
||||||
|
if (this.$targetInput.is(':disabled')) {
|
||||||
|
this.$element.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.bind();
|
||||||
|
this.oldValue = this.$targetInput.val();
|
||||||
|
|
||||||
|
var dateNow = new Date();
|
||||||
|
var month = dateNow.getMonth() + 1;
|
||||||
|
var date = dateNow.getDate();
|
||||||
|
|
||||||
|
month = month < 8 ? '0' + month : month;
|
||||||
|
date = date < 10 ? '0' + date : date;
|
||||||
|
|
||||||
|
this.dateValueNow = dateNow.getFullYear() + '-' + month + '-' + date;
|
||||||
|
},
|
||||||
|
|
||||||
|
bind: function() {
|
||||||
|
var pickerOptions = {
|
||||||
|
timeFormat: 'H:i',
|
||||||
|
showOn: null,
|
||||||
|
wrapHours: false,
|
||||||
|
scrollDefault: 'now'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.isDateTimePicker) {
|
||||||
|
this.$targetInput
|
||||||
|
.qorTimepicker(pickerOptions)
|
||||||
|
.on(EVENT_CHANGE_TIME, $.proxy(this.changeTime, this))
|
||||||
|
.on(EVENT_BLUR, $.proxy(this.blur, this))
|
||||||
|
.on(EVENT_FOCUS, $.proxy(this.focus, this))
|
||||||
|
.on(EVENT_KEYDOWN, $.proxy(this.keydown, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$element.on(EVENT_CLICK, $.proxy(this.show, this));
|
||||||
|
},
|
||||||
|
|
||||||
|
unbind: function() {
|
||||||
|
this.$element.off(EVENT_CLICK, this.show);
|
||||||
|
|
||||||
|
if (this.isDateTimePicker) {
|
||||||
|
this.$targetInput
|
||||||
|
.off(EVENT_CHANGE_TIME, this.changeTime)
|
||||||
|
.off(EVENT_BLUR, this.blur)
|
||||||
|
.off(EVENT_FOCUS, this.focus)
|
||||||
|
.off(EVENT_KEYDOWN, this.keydown);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
focus: function() {},
|
||||||
|
|
||||||
|
blur: function() {
|
||||||
|
var inputValue = this.$targetInput.val();
|
||||||
|
var inputArr = inputValue.split(' ');
|
||||||
|
var inputArrLen = inputArr.length;
|
||||||
|
|
||||||
|
var tempValue;
|
||||||
|
var newDateValue;
|
||||||
|
var newTimeValue;
|
||||||
|
var isDate;
|
||||||
|
var isTime;
|
||||||
|
var splitSym;
|
||||||
|
|
||||||
|
var timeReg = /\d{1,2}:\d{1,2}/;
|
||||||
|
var dateReg = /^\d{4}-\d{1,2}-\d{1,2}/;
|
||||||
|
|
||||||
|
if (!inputValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputArrLen == 1) {
|
||||||
|
if (dateReg.test(inputArr[0])) {
|
||||||
|
newDateValue = inputArr[0];
|
||||||
|
newTimeValue = '00:00';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeReg.test(inputArr[0])) {
|
||||||
|
newDateValue = this.dateValueNow;
|
||||||
|
newTimeValue = inputArr[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < inputArrLen; i++) {
|
||||||
|
// check for date && time
|
||||||
|
isDate = dateReg.test(inputArr[i]);
|
||||||
|
isTime = timeReg.test(inputArr[i]);
|
||||||
|
|
||||||
|
if (isDate) {
|
||||||
|
newDateValue = inputArr[i];
|
||||||
|
splitSym = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTime) {
|
||||||
|
newTimeValue = inputArr[i];
|
||||||
|
splitSym = ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
tempValue = inputArr[i].split(splitSym);
|
||||||
|
|
||||||
|
for (var j = 0; j < tempValue.length; j++) {
|
||||||
|
if (tempValue[j].length < 2) {
|
||||||
|
tempValue[j] = '0' + tempValue[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDate) {
|
||||||
|
newDateValue = tempValue.join(splitSym);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTime) {
|
||||||
|
newTimeValue = tempValue.join(splitSym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.checkDate(newDateValue) && this.checkTime(newTimeValue)) {
|
||||||
|
this.$targetInput.val(newDateValue + ' ' + newTimeValue);
|
||||||
|
this.oldValue = this.$targetInput.val();
|
||||||
|
} else {
|
||||||
|
this.$targetInput.val(this.oldValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
keydown: function(e) {
|
||||||
|
var keycode = e.keyCode;
|
||||||
|
var keys = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 8, 37, 38, 39, 40, 27, 32, 20, 189, 16, 186, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105];
|
||||||
|
if (keys.indexOf(keycode) == -1) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
checkDate: function(value) {
|
||||||
|
var regCheckDate = /^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{1,2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/;
|
||||||
|
return regCheckDate.test(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
checkTime: function(value) {
|
||||||
|
var regCheckTime = /^([01]\d|2[0-3]):?([0-5]\d)$/;
|
||||||
|
return regCheckTime.test(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
changeTime: function() {
|
||||||
|
var $targetInput = this.$targetInput;
|
||||||
|
|
||||||
|
var oldValue = this.oldValue;
|
||||||
|
var timeReg = /\d{1,2}:\d{1,2}/;
|
||||||
|
var hasTime = timeReg.test(oldValue);
|
||||||
|
var selectedTime = $targetInput
|
||||||
|
.data()
|
||||||
|
.timepickerObj.list.find(CLASS_TIME_SELECTED)
|
||||||
|
.html();
|
||||||
|
var newValue;
|
||||||
|
|
||||||
|
if (!oldValue) {
|
||||||
|
newValue = this.dateValueNow + ' ' + selectedTime;
|
||||||
|
} else if (hasTime) {
|
||||||
|
newValue = oldValue.replace(timeReg, selectedTime);
|
||||||
|
} else {
|
||||||
|
newValue = oldValue + ' ' + selectedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetInput.val(newValue);
|
||||||
|
$targetInput.trigger('change');
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function() {
|
||||||
|
if (!this.isDateTimePicker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$targetInput.qorTimepicker('show');
|
||||||
|
this.oldValue = this.$targetInput.val();
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.unbind();
|
||||||
|
this.$targetInput.qorTimepicker('remove');
|
||||||
|
this.$element.removeData(NAMESPACE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QorTimepicker.DEFAULTS = {};
|
||||||
|
|
||||||
|
QorTimepicker.plugin = function(option) {
|
||||||
|
return this.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var data = $this.data(NAMESPACE);
|
||||||
|
var options;
|
||||||
|
var fn;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
if (!$.fn.qorDatepicker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/destroy/.test(option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
options = $.extend(true, {}, $this.data(), typeof option === 'object' && option);
|
||||||
|
$this.data(NAMESPACE, (data = new QorTimepicker(this, options)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof option === 'string' && $.isFunction((fn = data[option]))) {
|
||||||
|
fn.apply(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
var selector = '[data-toggle="qor.timepicker"]';
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.on(EVENT_DISABLE, function(e) {
|
||||||
|
QorTimepicker.plugin.call($(selector, e.target), 'destroy');
|
||||||
|
})
|
||||||
|
.on(EVENT_ENABLE, function(e) {
|
||||||
|
QorTimepicker.plugin.call($(selector, e.target));
|
||||||
|
})
|
||||||
|
.triggerHandler(EVENT_ENABLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
return QorTimepicker;
|
||||||
|
});
|
||||||
2
app/views/qor/assets/javascripts/qor_admin_default.js
Normal file
2
app/views/qor/assets/javascripts/qor_admin_default.js
Normal file
File diff suppressed because one or more lines are too long
65
app/views/qor/assets/javascripts/vendors.js
Normal file
65
app/views/qor/assets/javascripts/vendors.js
Normal file
File diff suppressed because one or more lines are too long
10
app/views/qor/assets/javascripts/vendors/cropper.min.js
vendored
Normal file
10
app/views/qor/assets/javascripts/vendors/cropper.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
app/views/qor/assets/javascripts/vendors/jquery.min.js
vendored
Normal file
2
app/views/qor/assets/javascripts/vendors/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
app/views/qor/assets/javascripts/vendors/jquery.timepicker.min.js
vendored
Normal file
7
app/views/qor/assets/javascripts/vendors/jquery.timepicker.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
9
app/views/qor/assets/javascripts/vendors/material.min.js
vendored
Normal file
9
app/views/qor/assets/javascripts/vendors/material.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
app/views/qor/assets/javascripts/vendors/moment.min.js
vendored
Normal file
7
app/views/qor/assets/javascripts/vendors/moment.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
app/views/qor/assets/javascripts/vendors/mustache.min.js
vendored
Normal file
1
app/views/qor/assets/javascripts/vendors/mustache.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
app/views/qor/assets/javascripts/vendors/redactor.min.js
vendored
Normal file
7
app/views/qor/assets/javascripts/vendors/redactor.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
app/views/qor/assets/javascripts/vendors/redactor.source.min.js
vendored
Normal file
10
app/views/qor/assets/javascripts/vendors/redactor.source.min.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
Redactor Plugins
|
||||||
|
|
||||||
|
This plugin allows users to look through and edit text's HTML source code.
|
||||||
|
Developers may extend and enhance this plugin to bring even more HTML-related source code features to the users.
|
||||||
|
This plugin is only compatible with Redactor II 1.0.1 or higher.
|
||||||
|
|
||||||
|
https://imperavi.com/redactor/plugins/source/
|
||||||
|
*/
|
||||||
|
!function(t){t.Redactor.prototype.source=function(){return{init:function(){var e=this.button.addFirst("html","HTML");this.button.addCallback(e,this.source.toggle);var s={width:"100%",margin:"0",background:"#111","box-sizing":"border-box",color:"rgba(255, 255, 255, .8)","font-size":"14px",outline:"none",padding:"16px","line-height":"22px","font-family":'Menlo, Monaco, Consolas, "Courier New", monospace'};this.source.$textarea=t("<textarea />"),this.source.$textarea.css(s).hide(),"textarea"===this.opts.type?this.core.box().append(this.source.$textarea):this.core.box().after(this.source.$textarea),this.core.element().on("destroy.callback.redactor",t.proxy(function(){this.source.$textarea.remove()},this))},toggle:function(){return this.source.$textarea.hasClass("open")?this.source.hide():this.source.show()},setCaretOnShow:function(){this.source.offset=this.offset.get();t(window).scrollTop(),this.core.editor().innerWidth(),this.core.editor().innerHeight();this.source.start=0,this.source.end=0;var e=t("<div/>").append(t.parseHTML(this.core.editor().html(),document,!0)),s=e.find("span.redactor-selection-marker");if(s.length>0){var r=e.html().replace(/&/g,"&");1===s.length?(this.source.start=this.utils.strpos(r,e.find("#selection-marker-1").prop("outerHTML")),this.source.end=this.source.start):2===s.length&&(this.source.start=this.utils.strpos(r,e.find("#selection-marker-1").prop("outerHTML")),this.source.end=this.utils.strpos(r,e.find("#selection-marker-2").prop("outerHTML"))-e.find("#selection-marker-1").prop("outerHTML").toString().length)}},setCaretOnHide:function(t){if(this.source.start=this.source.$textarea.get(0).selectionStart,this.source.end=this.source.$textarea.get(0).selectionEnd,this.source.start>this.source.end&&this.source.end>0){var e=this.source.end,s=this.source.start;this.source.start=e,this.source.end=s}if(this.source.start=this.source.enlargeOffset(t,this.source.start),this.source.end=this.source.enlargeOffset(t,this.source.end),t=t.substr(0,this.source.start)+this.marker.html(1)+t.substr(this.source.start),this.source.end>this.source.start){var r=this.marker.html(1).toString().length;t=t.substr(0,this.source.end+r)+this.marker.html(2)+t.substr(this.source.end+r)}return t},hide:function(){this.source.$textarea.removeClass("open").hide(),this.source.$textarea.off(".redactor-source");var t=this.source.$textarea.val();t=this.paragraphize.load(t),t=this.source.setCaretOnHide(t),this.code.start(t),this.button.enableAll(),this.core.editor().show().focus(),this.selection.restore()},show:function(){this.selection.save(),this.source.setCaretOnShow();var e=this.core.editor().innerHeight(),s=this.code.get();s=s.replace(/\n\n\n/g,"\n"),s=s.replace(/\n\n/g,"\n"),this.core.editor().hide(),this.button.disableAll("html"),this.source.$textarea.val(s).height(e).addClass("open").show(),this.source.$textarea.on("keyup.redactor-source",t.proxy(function(){"textarea"===this.opts.type&&this.core.textarea().val(this.source.$textarea.val())},this)),this.marker.remove(),t(window).scrollTop(scroll),this.source.$textarea[0].setSelectionRange&&this.source.$textarea[0].setSelectionRange(this.source.start,this.source.end),this.source.$textarea[0].scrollTop=0,setTimeout(t.proxy(function(){this.source.$textarea.focus()},this),0)},enlargeOffset:function(t,e){var s=t.length,r=0;if(">"===t[e])r++;else for(var o=e;s>=o&&(r++,">"!==t[o]);o++)if("<"===t[o]||o===s){r=0;break}return e+r}}}}(jQuery);
|
||||||
1
app/views/qor/assets/javascripts/vendors/select2.min.js
vendored
Normal file
1
app/views/qor/assets/javascripts/vendors/select2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
app/views/qor/assets/javascripts/vendors/underscore.min.js
vendored
Normal file
6
app/views/qor/assets/javascripts/vendors/underscore.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
app/views/qor/assets/stylesheets/app.css
Normal file
1
app/views/qor/assets/stylesheets/app.css
Normal file
File diff suppressed because one or more lines are too long
BIN
app/views/qor/assets/stylesheets/chosen-sprite.png
Normal file
BIN
app/views/qor/assets/stylesheets/chosen-sprite.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 538 B |
BIN
app/views/qor/assets/stylesheets/chosen-sprite@2x.png
Normal file
BIN
app/views/qor/assets/stylesheets/chosen-sprite@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 738 B |
1
app/views/qor/assets/stylesheets/datetimepicker.css
Normal file
1
app/views/qor/assets/stylesheets/datetimepicker.css
Normal file
File diff suppressed because one or more lines are too long
65
app/views/qor/assets/stylesheets/fonts.css
Normal file
65
app/views/qor/assets/stylesheets/fonts.css
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(../fonts/MaterialIcons.woff) format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto Italic'), local('Roboto-Italic'), url(//fonts.gstatic.com/s/roboto/v20/KFOkCnqEu92Fr1Mu52xM.woff) format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Roboto Light'), local('Roboto-Light'), url(//fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5vAA.woff) format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Roboto'), local('Roboto-Regular'), url(//fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Me5g.woff) format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: local('Roboto Medium'), local('Roboto-Medium'), url(//fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9vAA.woff) format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Roboto Bold'), local('Roboto-Bold'), url(//fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlvAA.woff) format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-icons {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 24px; /* Preferred icon size */
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
line-height: 1;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
word-break: normal;
|
||||||
|
|
||||||
|
/* Support for all WebKit browsers. */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
/* Support for Safari and Chrome. */
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
|
||||||
|
/* Support for Firefox. */
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Support for IE. */
|
||||||
|
-webkit-font-feature-settings: 'liga';
|
||||||
|
-moz-font-feature-settings: 'liga';
|
||||||
|
font-feature-settings: 'liga';
|
||||||
|
-ms-font-feature-settings: 'liga';
|
||||||
|
}
|
||||||
1
app/views/qor/assets/stylesheets/qor.css
Normal file
1
app/views/qor/assets/stylesheets/qor.css
Normal file
File diff suppressed because one or more lines are too long
31
app/views/qor/assets/stylesheets/qor_admin_default.css
Normal file
31
app/views/qor/assets/stylesheets/qor_admin_default.css
Normal file
File diff suppressed because one or more lines are too long
BIN
app/views/qor/assets/stylesheets/redactor-font.eot
Normal file
BIN
app/views/qor/assets/stylesheets/redactor-font.eot
Normal file
Binary file not shown.
53
app/views/qor/assets/stylesheets/scss/_mixins.scss
Normal file
53
app/views/qor/assets/stylesheets/scss/_mixins.scss
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// Mixins
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
// Material Design Lite's mixins
|
||||||
|
@import "mdl/mixins";
|
||||||
|
|
||||||
|
|
||||||
|
// Clearfix
|
||||||
|
//
|
||||||
|
// For modern browsers
|
||||||
|
// 1. The space content is one way to avoid an Opera bug when the
|
||||||
|
// contenteditable attribute is included anywhere else in the document.
|
||||||
|
// Otherwise it causes space to appear at the top and bottom of elements
|
||||||
|
// that are clearfixed.
|
||||||
|
// 2. The use of `table` rather than `block` is only necessary if using
|
||||||
|
// `:before` to contain the top-margins of child elements.
|
||||||
|
//
|
||||||
|
// Source: http://nicolasgallagher.com/micro-clearfix-hack/
|
||||||
|
|
||||||
|
@mixin clearfix() {
|
||||||
|
&:before,
|
||||||
|
&:after {
|
||||||
|
content: " ";
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin text-hide() {
|
||||||
|
font: 0/0 a;
|
||||||
|
color: transparent;
|
||||||
|
text-shadow: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text overflow
|
||||||
|
// Requires inline-block or block for proper styling
|
||||||
|
|
||||||
|
@mixin text-overflow() {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin shadow-2dp-bottom() {
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, $shadow-key-penumbra-opacity),
|
||||||
|
0 3px 1px -2px rgba(0, 0, 0, $shadow-key-umbra-opacity),
|
||||||
|
0 3px 5px 0 rgba(0, 0, 0, $shadow-ambient-shadow-opacity);
|
||||||
|
}
|
||||||
19
app/views/qor/assets/stylesheets/scss/_variables.scss
Normal file
19
app/views/qor/assets/stylesheets/scss/_variables.scss
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
// Variables
|
||||||
|
// --------------------------------------------------
|
||||||
|
// Material Design Lite's variables
|
||||||
|
@import "mdl/variables"; // Customize palette
|
||||||
|
// Download: https://storage.googleapis.com/code.getmdl.io/1.0.3/material.blue-pink.min.css
|
||||||
|
$color-primary: $palette-light-blue-500;
|
||||||
|
$color-primary-dark: $palette-light-blue-700; // Z-index master list
|
||||||
|
//
|
||||||
|
// Warning: Avoid customizing these values. They're used for a bird's eye view
|
||||||
|
// of components dependent on the z-axis and are designed to all work together.
|
||||||
|
$zindex-fixer: 990;
|
||||||
|
$zindex-slideout: 1000;
|
||||||
|
$zindex-bottomsheets: 1005;
|
||||||
|
$zindex-modal: 1010;
|
||||||
|
$color-main-header: #0277bd;
|
||||||
|
$color-slideout-header: unquote("rgb(#{$color-primary})");
|
||||||
|
$color-dash: #ededed;
|
||||||
|
$color-body-bg: #f5f5f5;
|
||||||
|
$width-bottomsheet: 640px;
|
||||||
21
app/views/qor/assets/stylesheets/scss/app.scss
Normal file
21
app/views/qor/assets/stylesheets/scss/app.scss
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
@import 'variables';
|
||||||
|
@import 'mixins';
|
||||||
|
@import 'app/fonts';
|
||||||
|
@import 'app/layout';
|
||||||
|
@import 'app/typography';
|
||||||
|
@import 'app/forms';
|
||||||
|
@import 'app/select';
|
||||||
|
@import 'app/buttons';
|
||||||
|
@import 'app/labels';
|
||||||
|
@import 'app/table';
|
||||||
|
@import 'app/search-center';
|
||||||
|
@import 'app/menu';
|
||||||
|
@import 'app/qor-icons';
|
||||||
|
@import 'app/alerts';
|
||||||
|
@import 'app/actions';
|
||||||
|
@import 'app/sections';
|
||||||
|
@import 'app/pagination';
|
||||||
|
@import 'app/tabs';
|
||||||
|
@import 'app/utilities';
|
||||||
|
@import 'app/mobile';
|
||||||
|
@import 'app/print';
|
||||||
131
app/views/qor/assets/stylesheets/scss/app/_actions.scss
Normal file
131
app/views/qor/assets/stylesheets/scss/app/_actions.scss
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
.mdl-button {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.qor-actions {
|
||||||
|
float: left;
|
||||||
|
min-height: 32px;
|
||||||
|
margin-right: 8px;
|
||||||
|
padding: 8px 0;
|
||||||
|
@include clearfix();
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
.qor-selector {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
.mdl-button {
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-selector,
|
||||||
|
.qor-action--text,
|
||||||
|
.qor-action--label,
|
||||||
|
.qor-action--select,
|
||||||
|
.qor-action--button {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-action--select {
|
||||||
|
height: 32px;
|
||||||
|
border: 2px solid unquote('rgb(#{$color-primary})');
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-action--label {
|
||||||
|
display: inline-block;
|
||||||
|
height: 28px;
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 28px;
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.54)');
|
||||||
|
background-color: #fff;
|
||||||
|
border: 2px solid unquote('rgba(#{$color-black}, 0.12)');
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.54)');
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
padding-right: 0;
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.87)');
|
||||||
|
border-color: unquote('rgb(#{$color-primary})');
|
||||||
|
}
|
||||||
|
|
||||||
|
> i {
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
height: 28px;
|
||||||
|
margin-left: 6px;
|
||||||
|
padding-left: 2px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 28px;
|
||||||
|
background-color: unquote('rgb(#{$color-primary})');
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .qor-action--select,
|
||||||
|
+ .qor-action--label {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.qor-action-bulk-buttons,
|
||||||
|
.qor-action-forms {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
.qor-action--button {
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
|
||||||
|
+ .qor-action--button {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-action-bulk-edit {
|
||||||
|
float: left;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
.qor-action-forms {
|
||||||
|
padding-bottom: 0;
|
||||||
|
.qor-form__actions {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
> .qor-action-button {
|
||||||
|
margin-right: 24px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
> .action-form {
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
> .action-form,
|
||||||
|
.qor-form-section,
|
||||||
|
.qor-form__actions {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
.qor-form__actions {
|
||||||
|
.mdl-button {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-action-disabled{
|
||||||
|
background-color: rgba(0,0,0,.12) !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
color: rgba(0,0,0,.2) !important;
|
||||||
|
}
|
||||||
145
app/views/qor/assets/stylesheets/scss/app/_alerts.scss
Normal file
145
app/views/qor/assets/stylesheets/scss/app/_alerts.scss
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
// Alerts
|
||||||
|
// --------------------------------------------------
|
||||||
|
.qor-alert {
|
||||||
|
padding: 24px 48px 0 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
color: unquote('rgb(#{$palette-grey-700})');
|
||||||
|
background-color: unquote('rgb(#{$palette-grey-100})');
|
||||||
|
position: fixed;
|
||||||
|
z-index: 99999;
|
||||||
|
margin: 0;
|
||||||
|
left: 50%;
|
||||||
|
top: 0;
|
||||||
|
transform: translate(-50%, -110%);
|
||||||
|
|
||||||
|
justify-content: space-between;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
will-change: transform;
|
||||||
|
transition: transform 0.25s cubic-bezier(0.4, 0, 1, 1);
|
||||||
|
|
||||||
|
@include shadow-2dp();
|
||||||
|
@include clearfix();
|
||||||
|
|
||||||
|
&.qor-alert__active {
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
> button {
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 9px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-alert-message {
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-alert--success {
|
||||||
|
color: unquote('rgb(#{$palette-blue-700})');
|
||||||
|
background-color: unquote('rgb(#{$palette-blue-100})');
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-alert--error {
|
||||||
|
color: unquote('rgb(#{$palette-pink-700})');
|
||||||
|
background-color: unquote('rgb(#{$palette-pink-100})');
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdl-dialog-bg {
|
||||||
|
position: fixed;
|
||||||
|
background: unquote('rgba(#{$color-black}, 0.54)');
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 9998;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errors
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
.qor-error {
|
||||||
|
background-color: #fff;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
> li {
|
||||||
|
+ li {
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-left: 32px;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-weight: normal;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
color: unquote('rgb(#{$color-accent})');
|
||||||
|
|
||||||
|
> i {
|
||||||
|
position: absolute;
|
||||||
|
top: -3px;
|
||||||
|
left: -5px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-modal {
|
||||||
|
.qor-error {
|
||||||
|
margin: 24px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#dialog {
|
||||||
|
display: none;
|
||||||
|
.mdl-dialog {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
width: -moz-fit-content;
|
||||||
|
width: -webkit-fit-content;
|
||||||
|
width: fit-content;
|
||||||
|
height: -moz-fit-content;
|
||||||
|
height: -webkit-fit-content;
|
||||||
|
height: fit-content;
|
||||||
|
margin: auto;
|
||||||
|
padding: 1em;
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
display: block;
|
||||||
|
z-index: 9999;
|
||||||
|
top: 200px;
|
||||||
|
max-width: 50%;
|
||||||
|
min-width: 30%;
|
||||||
|
border: 2px solid rgba(0, 0, 0, 0.05);
|
||||||
|
.mdl-dialog__content {
|
||||||
|
> p {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
margin: 0;
|
||||||
|
width: 40px;
|
||||||
|
&.mdl-dialog__message {
|
||||||
|
padding: 2px 0 0 16px;
|
||||||
|
width: calc(100% - 100px);
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #ff0600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button[data-type='cancel'] {
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.54)');
|
||||||
|
}
|
||||||
|
.mdl-dialog__content {
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.75)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/views/qor/assets/stylesheets/scss/app/_buttons.scss
Normal file
24
app/views/qor/assets/stylesheets/scss/app/_buttons.scss
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Buttons
|
||||||
|
// --------------------------------------------------
|
||||||
|
.qor-button--small {
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-button--new,
|
||||||
|
.qor-button--edit {
|
||||||
|
position: fixed;
|
||||||
|
right: 32px;
|
||||||
|
bottom: 32px;
|
||||||
|
z-index: 3;
|
||||||
|
@include shadow-4dp();
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-button--accent {
|
||||||
|
color: #fff;
|
||||||
|
background-color: unquote("rgb(#{$color-accent})") !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-button--muted {
|
||||||
|
color: unquote("rgba(#{$color-black}, 0.54)");
|
||||||
|
}
|
||||||
72
app/views/qor/assets/stylesheets/scss/app/_fonts.scss
Normal file
72
app/views/qor/assets/stylesheets/scss/app/_fonts.scss
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// // Fonts
|
||||||
|
// // --------------------------------------------------
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: normal;
|
||||||
|
// font-weight: 200;
|
||||||
|
// src: local('Roboto Thin'), local('Roboto-Thin'), url(../fonts/Roboto-Thin.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: italic;
|
||||||
|
// font-weight: 200;
|
||||||
|
// src: local('Roboto ThinItalic'), local('Roboto-ThinItalic'), url(../fonts/Roboto-ThinItalic.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: normal;
|
||||||
|
// font-weight: 300;
|
||||||
|
// src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/Roboto-Light.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: italic;
|
||||||
|
// font-weight: 300;
|
||||||
|
// src: local('Roboto LightItalic'), local('Roboto-LightItalic'), url(../fonts/Roboto-LightItalic.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: normal;
|
||||||
|
// font-weight: 400;
|
||||||
|
// src: local('Roboto Regular'), local('Roboto-Regular'), url(../fonts/Roboto-Regular.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: italic;
|
||||||
|
// font-weight: 400;
|
||||||
|
// src: local('Roboto Italic'), local('Roboto-Italic'), url(../fonts/Roboto-Italic.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: normal;
|
||||||
|
// font-weight: 500;
|
||||||
|
// src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/Roboto-Medium.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: italic;
|
||||||
|
// font-weight: 500;
|
||||||
|
// src: local('Roboto MediumItalic'), local('Roboto-MediumItalic'), url(../fonts/Roboto-MediumItalic.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: normal;
|
||||||
|
// font-weight: 700;
|
||||||
|
// src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/Roboto-Bold.ttf) format('truetype');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @font-face {
|
||||||
|
// font-family: 'Roboto';
|
||||||
|
// font-style: italic;
|
||||||
|
// font-weight: 700;
|
||||||
|
// src: local('Roboto BoldItalic'), local('Roboto-BoldItalic'), url(../fonts/Roboto-BoldItalic.ttf) format('truetype');
|
||||||
|
// }
|
||||||
471
app/views/qor/assets/stylesheets/scss/app/_forms.scss
Normal file
471
app/views/qor/assets/stylesheets/scss/app/_forms.scss
Normal file
@@ -0,0 +1,471 @@
|
|||||||
|
// Forms
|
||||||
|
// --------------------------------------------------
|
||||||
|
// Form
|
||||||
|
// -------------------------
|
||||||
|
.qor-form-container {
|
||||||
|
margin: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-slideout__body .qor-form-container {
|
||||||
|
margin: 24px 0;
|
||||||
|
padding: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-textarea__input {
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
outline: none;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-form__actions {
|
||||||
|
margin-top: 24px;
|
||||||
|
@include clearfix();
|
||||||
|
.percent-complete {
|
||||||
|
margin-top: -22px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
#qor-submit-loading {
|
||||||
|
float: right;
|
||||||
|
.mdl-spinner {
|
||||||
|
margin: 0 24px 24px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mdl-button {
|
||||||
|
float: right;
|
||||||
|
+ .mdl-button {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdl-switch {
|
||||||
|
width: auto;
|
||||||
|
&.is-upgraded {
|
||||||
|
padding-right: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdl-textfield textarea.mdl-textfield__input {
|
||||||
|
overflow: initial !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search Form
|
||||||
|
// -------------------------
|
||||||
|
.qor-search-container {
|
||||||
|
float: right;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to .qor-page__header
|
||||||
|
.qor-search,
|
||||||
|
.qor-global-search {
|
||||||
|
height: 56px;
|
||||||
|
padding: 14px 6px;
|
||||||
|
.mdl-button {
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
.qor-search__label {
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.54)');
|
||||||
|
}
|
||||||
|
.qor-search__input {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.qor-search__clear {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.is-dirty,
|
||||||
|
&.is-focused {
|
||||||
|
.qor-search__label {
|
||||||
|
&,
|
||||||
|
&:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.qor-search__clear {
|
||||||
|
right: -7px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field
|
||||||
|
// -------------------------
|
||||||
|
.qor-field__label {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.54)');
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-field__value {
|
||||||
|
display: block;
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-field__input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-field__block {
|
||||||
|
display: block;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.chosen-container {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-field__show {
|
||||||
|
display: none;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-upgraded] > .qor-field__show {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-page__show {
|
||||||
|
.qor-field__show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.qor-field__edit,
|
||||||
|
.qor-fieldset__delete,
|
||||||
|
.qor-fieldset__add {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-page__edit {
|
||||||
|
.qor-field__show {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.qor-field__edit,
|
||||||
|
.qor-fieldset__delete {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.qor-fieldset__add {
|
||||||
|
display: inline-block;
|
||||||
|
&.mdl-menu__item {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button.qor-fieldset__add,
|
||||||
|
.qor-fieldset__add-promotion,
|
||||||
|
.qor-button__icon-add {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0;
|
||||||
|
&:hover,
|
||||||
|
&:active,
|
||||||
|
&:focus:not(:active) {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-field {
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
&.is-error {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
.qor-field__label,
|
||||||
|
.qor-field__error,
|
||||||
|
.mdl-textfield__label {
|
||||||
|
color: unquote('rgb(#{$color-accent})');
|
||||||
|
}
|
||||||
|
.qor-field__error {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
> i {
|
||||||
|
font-size: 18px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
+ span {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mdl-textfield,
|
||||||
|
.qor-field__block {
|
||||||
|
+ .qor-field__error {
|
||||||
|
margin-top: -16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mdl-textfield__label {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.mdl-checkbox__label {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom modifier for .mdl-textfield
|
||||||
|
.qor-field {
|
||||||
|
.mdl-textfield__label {
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.54)');
|
||||||
|
font-size: 12px;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
.mdl-textfield__input {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.mdl-textfield.is-dirty .mdl-textfield__label,
|
||||||
|
.mdl-textfield.has-placeholder .mdl-textfield__label {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-textfield--condensed {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
.mdl-textfield__label {
|
||||||
|
top: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
&:after {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mdl-textfield__input {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// File input
|
||||||
|
// -------------------------
|
||||||
|
.qor-file {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
margin-top: 8px;
|
||||||
|
&.is-svg {
|
||||||
|
.qor-file__list {
|
||||||
|
> ul {
|
||||||
|
> li {
|
||||||
|
text-align: center;
|
||||||
|
img {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-file__list {
|
||||||
|
overflow: hidden;
|
||||||
|
> ul {
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
> li {
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
display: block;
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border: 1px solid unquote('rgba(#{$color-black}, 0.12)');
|
||||||
|
background-color: unquote('rgb(#{$color-white})');
|
||||||
|
overflow: hidden;
|
||||||
|
> span {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: unquote('rgba(#{$color-white}, 0.5)');
|
||||||
|
&:first-letter {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 160px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.qor-file__list-item {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 150px;
|
||||||
|
height: 80px;
|
||||||
|
border: 1px solid unquote('rgba(#{$color-black}, 0.12)');
|
||||||
|
background-color: unquote('rgb(#{$color-white})');
|
||||||
|
margin-top: 12px;
|
||||||
|
.qor-file__action {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
|
display: block;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: unquote('rgba(#{$color-black}, 0.75)');
|
||||||
|
opacity: 0;
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
color: #fff;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
margin-top: 16%;
|
||||||
|
&:hover {
|
||||||
|
i {
|
||||||
|
color: unquote('rgb(#{$color-primary})');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
.qor-file__action {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
display: flex;
|
||||||
|
font-size: 12px;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 1.1;
|
||||||
|
height: 80px;
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
max-height: 80px;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 12px;
|
||||||
|
text-align: center;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fieldset
|
||||||
|
// -------------------------
|
||||||
|
.qor-fieldset {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 16px 24px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
background-color: #fff;
|
||||||
|
&.qor-fieldset--new {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.mdl-textfield__input {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.qor-fieldset {
|
||||||
|
background-color: unquote('rgb(#{$palette-grey-50})');
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid unquote('rgba(#{$color-black}, 0.12)');
|
||||||
|
.qor-fieldset {
|
||||||
|
background-color: #fff;
|
||||||
|
.qor-fieldset {
|
||||||
|
background-color: unquote('rgb(#{$palette-grey-50})');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-fieldset__delete {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-fieldset__alert {
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section
|
||||||
|
// ------------------------
|
||||||
|
.qor-section-columns-2 .qor-field {
|
||||||
|
width: 50%;
|
||||||
|
float: left;
|
||||||
|
padding-right: 40px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
.mdl-textfield .qor-field__edit {
|
||||||
|
margin-top: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-section-columns-3 .qor-field {
|
||||||
|
width: 33.33%;
|
||||||
|
float: left;
|
||||||
|
padding-right: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion-coupons .qor-section-columns-3 .qor-field {
|
||||||
|
&:first-child {
|
||||||
|
width: 50%;
|
||||||
|
.mdl-textfield {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
margin-top: 36px;
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
width: 60px;
|
||||||
|
.mdl-textfield__label {
|
||||||
|
overflow: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-input-placeholder {
|
||||||
|
/* WebKit, Blink, Edge */
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.12)');
|
||||||
|
}
|
||||||
|
|
||||||
|
::-moz-placeholder {
|
||||||
|
/* Mozilla Firefox 19+ */
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.12)');
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:-ms-input-placeholder {
|
||||||
|
/* Internet Explorer 10-11 */
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.12)');
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdl-checkbox__label {
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
.mdl-checkbox {
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
102
app/views/qor/assets/stylesheets/scss/app/_icons.scss
Normal file
102
app/views/qor/assets/stylesheets/scss/app/_icons.scss
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
// Icons
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
// http://google.github.io/material-design-icons/#icon-font-for-the-web
|
||||||
|
|
||||||
|
@mixin material-icons{
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 24px; /* Preferred icon size */
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
line-height: 1;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
word-break: normal;
|
||||||
|
|
||||||
|
/* Support for all WebKit browsers. */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
/* Support for Safari and Chrome. */
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
|
||||||
|
/* Support for Firefox. */
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Support for IE. */
|
||||||
|
-webkit-font-feature-settings: 'liga';
|
||||||
|
-moz-font-feature-settings: 'liga';
|
||||||
|
font-feature-settings: 'liga';
|
||||||
|
-ms-font-feature-settings: 'liga';
|
||||||
|
}
|
||||||
|
|
||||||
|
.md,
|
||||||
|
.material-icons {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 24px; /* Preferred icon size */
|
||||||
|
display: inline-block;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
line-height: 1;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
word-break: normal;
|
||||||
|
|
||||||
|
/* Support for all WebKit browsers. */
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
/* Support for Safari and Chrome. */
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
|
||||||
|
/* Support for Firefox. */
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Support for IE. */
|
||||||
|
-webkit-font-feature-settings: 'liga';
|
||||||
|
-moz-font-feature-settings: 'liga';
|
||||||
|
font-feature-settings: 'liga';
|
||||||
|
-ms-font-feature-settings: 'liga';
|
||||||
|
|
||||||
|
// Rules for sizing the icon.
|
||||||
|
&.md-14 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.md-18 {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.md-24 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.md-36 {
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.md-48 {
|
||||||
|
font-size: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rules for using icons as black on a light background.
|
||||||
|
&.md-dark {
|
||||||
|
color: rgba(0, 0, 0, 0.54);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.md-dark.md-inactive {
|
||||||
|
color: rgba(0, 0, 0, 0.26);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rules for using icons as white on a dark background.
|
||||||
|
&.md-light {
|
||||||
|
color: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.md-light.md-inactive {
|
||||||
|
color: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/views/qor/assets/stylesheets/scss/app/_labels.scss
Normal file
19
app/views/qor/assets/stylesheets/scss/app/_labels.scss
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
.qor-label {
|
||||||
|
display: inline;
|
||||||
|
padding: 1px 8px;
|
||||||
|
border: 1px solid unquote("rgba(#{$color-black}, 0.12)");
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1;
|
||||||
|
background-color: #fff;
|
||||||
|
color: unquote("rgba(#{$color-black}, 0.26)");
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
vertical-align: baseline;
|
||||||
|
border-radius: .25em;
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
border-color: unquote("rgba(#{$color-primary}, 0.87)");
|
||||||
|
color: unquote("rgb(#{$color-primary})");
|
||||||
|
}
|
||||||
|
}
|
||||||
318
app/views/qor/assets/stylesheets/scss/app/_layout.scss
Normal file
318
app/views/qor/assets/stylesheets/scss/app/_layout.scss
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
.qor-layout {
|
||||||
|
width: 100%;
|
||||||
|
.mdl-layout__content {
|
||||||
|
overflow: auto;
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-left: 240px;
|
||||||
|
margin-left: 0;
|
||||||
|
&.has-subnav {
|
||||||
|
padding-top: 56px;
|
||||||
|
}
|
||||||
|
> .qor-page__body {
|
||||||
|
> .qor-table-container {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-button {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #ccc;
|
||||||
|
border: 0 none #ffffff;
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: unquote('rgb(#{$color-primary})');
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb:active {
|
||||||
|
background: unquote('rgb(#{$color-primary})');
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
border: 0 none #ffffff;
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track:hover {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track:active {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-corner {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mdl-layout__header,
|
||||||
|
.mdl-layout__tab-bar {
|
||||||
|
background-color: $color-main-header;
|
||||||
|
}
|
||||||
|
.mdl-layout__header {
|
||||||
|
a.mdl-button--icon:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.mdl-layout__header-row {
|
||||||
|
> .mdl-button--icon,
|
||||||
|
.qor-search-container {
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.qor-search-container {
|
||||||
|
/* float: none; */
|
||||||
|
.qor-search {
|
||||||
|
height: 64px;
|
||||||
|
line-height: 64px;
|
||||||
|
padding: 0;
|
||||||
|
&.is-focused {
|
||||||
|
.mdl-textfield__label::after {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.mdl-button.mdl-button--colored {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.qor-search__label {
|
||||||
|
color: #fff;
|
||||||
|
top: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.mdl-layout.is-upgraded .mdl-layout__tab.is-active::after {
|
||||||
|
background: unquote('rgb(#{$color-white})');
|
||||||
|
}
|
||||||
|
.mdl-layout-text {
|
||||||
|
color: unquote('rgba(#{$color-white}, 0.54)');
|
||||||
|
}
|
||||||
|
.mdl-navigation__link > .material-icons {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.mdl-layout__drawer {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-layout__sidebar {
|
||||||
|
height: 100%;
|
||||||
|
> .sidebar-header {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 64px;
|
||||||
|
> a {
|
||||||
|
text-decoration: none;
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
&:first-child {
|
||||||
|
float: left;
|
||||||
|
display: block;
|
||||||
|
width: 110px;
|
||||||
|
height: 64px;
|
||||||
|
background: url(../images/logo.png) no-repeat center center;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
float: left;
|
||||||
|
width: 100px;
|
||||||
|
padding: 22px 10px;
|
||||||
|
color: #757575;
|
||||||
|
> .material-icons {
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
margin-left: 3px;
|
||||||
|
margin-right: 3px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .sidebar-userinfo {
|
||||||
|
height: 48px;
|
||||||
|
position: absolute;
|
||||||
|
top: 64px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
border-bottom: 1px solid unquote('rgba(#{$color-black}, 0.12)');
|
||||||
|
padding-left: 16px;
|
||||||
|
h5 {
|
||||||
|
font-size: 14px;
|
||||||
|
max-width: 70%;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
line-height: 48px;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 300;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
& > a {
|
||||||
|
float: right;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .sidebar-body {
|
||||||
|
position: absolute;
|
||||||
|
top: 112px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 40px;
|
||||||
|
left: 0;
|
||||||
|
overflow: visible;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
> .sidebar-footer {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-top: 1px solid unquote('rgba(#{$color-black}, 0.12)');
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-layout__content {
|
||||||
|
position: absolute; // Inherit body height with absolute position
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 56px;
|
||||||
|
min-height: 100%;
|
||||||
|
-webkit-transition: left 0.35s ease;
|
||||||
|
-o-transition: left 0.35s ease;
|
||||||
|
transition: left 0.35s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.has-subnav {
|
||||||
|
.qor-page__header {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.qor-page__header {
|
||||||
|
position: fixed;
|
||||||
|
top: 64px;
|
||||||
|
min-height: 48px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
padding: 0 24px;
|
||||||
|
width: calc(100% - 240px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 5000;
|
||||||
|
@include shadow-2dp-bottom();
|
||||||
|
@include clearfix();
|
||||||
|
.mdl-button {
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
.qor-search {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
+ .qor-page__body {
|
||||||
|
padding-top: 48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-page__footer {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdl-layout__content {
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-page__header .qor-page-subnav__header {
|
||||||
|
width: calc(100% + 48px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-page-subnav__header {
|
||||||
|
padding: 0 !important;
|
||||||
|
background-color: transparent;
|
||||||
|
margin: 0 -24px;
|
||||||
|
.mdl-layout__tab {
|
||||||
|
min-width: 128px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.mdl-layout__tab-bar {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-page__header-tabbar {
|
||||||
|
padding: 0;
|
||||||
|
background-color: $color-main-header;
|
||||||
|
.mdl-layout__tab-bar {
|
||||||
|
height: 48px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-view-all {
|
||||||
|
display: inline-block;
|
||||||
|
height: 32px;
|
||||||
|
margin-left: 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 32px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-decoration: none;
|
||||||
|
color: unquote('rgb(#{$color-primary})');
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdl-layout__header-row {
|
||||||
|
padding-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-page__tips {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
color: unquote('rgba(#{$color-black}, 0.75)');
|
||||||
|
margin-top: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qor-fieldset {
|
||||||
|
.qor-field + .qor-page__tips {
|
||||||
|
margin-top: -28px;
|
||||||
|
}
|
||||||
|
.qor-page__tips {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1024px) {
|
||||||
|
.qor-page__header {
|
||||||
|
width: 100%;
|
||||||
|
top: 56px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1025px) {
|
||||||
|
.mdl-layout--fixed-drawer > .mdl-layout__header .mdl-layout__header-row {
|
||||||
|
padding-left: 24px;
|
||||||
|
}
|
||||||
|
.qor-page__col-2 {
|
||||||
|
.qor-page__col-right {
|
||||||
|
width: calc(100% - 320px);
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.qor-page__col-left {
|
||||||
|
float: left;
|
||||||
|
width: 320px;
|
||||||
|
h5 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix refresh page sidebar height flash bug */
|
||||||
|
|
||||||
|
body > .mdl-layout {
|
||||||
|
bottom: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user