From f0b211f269df2b0bb10d5552d14aeb8991a750ed Mon Sep 17 00:00:00 2001 From: seshukm Date: Fri, 20 Jan 2017 17:43:08 +0530 Subject: GUI Code refactor GUI Code refactor for the sun release code. Issue-Id : CLIENT-11 Change-Id: I771cc25ff3c8ff7a4e939ce7baef7dd94a67974b Signed-off-by: seshukm --- .../common/thirdparty/animate/animate.min.css | 10 +- .../main/webapp/common/thirdparty/avalon/avalon.js | 11636 +- .../common/thirdparty/avalon/avalon.modern.js | 9868 +- .../backstretch/jquery.backstretch.min.js | 6 +- .../webapp/common/thirdparty/bootbox/LICENSE.md | 46 +- .../webapp/common/thirdparty/bootbox/README.md | 182 +- .../common/thirdparty/bootbox/bootbox.min.js | 10 +- .../daterangepicker-bs3.css | 638 +- .../bootstrap-daterangepicker/daterangepicker.js | 2514 +- .../thirdparty/bootstrap-daterangepicker/moment.js | 5614 +- .../bootstrap-daterangepicker/moment.min.js | 10 +- .../bootstrap-fileinput/css/fileinput.min.css | 20 +- .../bootstrap-fileinput/js/fileinput.min.js | 36 +- .../js/fileinput_locale_LANG.js | 88 +- .../bootstrap-fileinput/js/fileinput_locale_zh.js | 96 +- .../bootstrap-growl/bootstrap-growl.min.js | 2 +- .../bootstrap-growl/jquery.bootstrap-growl.min.js | 2 +- .../thirdparty/bootstrap-hover-dropdown/LICENSE | 46 +- .../thirdparty/bootstrap-hover-dropdown/README.md | 244 +- .../bootstrap-hover-dropdown.js | 28 +- .../bootstrap-hover-dropdown.min.js | 24 +- .../css/bootstrap-modal-bs3patch.css | 100 +- .../bootstrap-modal/css/bootstrap-modal.css | 428 +- .../bootstrap-modal/js/bootstrap-modal.js | 756 +- .../bootstrap-modal/js/bootstrap-modalmanager.js | 846 +- .../bootstrap-select/bootstrap-select.min.css | 14 +- .../bootstrap-select/bootstrap-select.min.js | 14 +- .../thirdparty/bootstrap-table/bootstrap-table.css | 626 +- .../thirdparty/bootstrap-table/bootstrap-table.js | 6124 +- .../bootstrap-table/bootstrap-table.min.js | 14 +- .../thirdparty/bootstrap-table/bootstrap.min.css | 12 +- .../jquery.bootstrap.wizard.min.js | 40 +- .../thirdparty/bootstrap/css/bootstrap-dt.css | 11608 +- .../thirdparty/bootstrap/css/bootstrap.min.css | 12 +- .../fonts/glyphicons-halflings-regular.svg | 574 +- .../common/thirdparty/bootstrap/js/bootstrap.js | 3902 +- .../thirdparty/bootstrap/js/bootstrap.min.js | 10 +- .../bootstrap/js/bootstrap2-typeahead.min.js | 40 +- .../main/webapp/common/thirdparty/cometd/cometd.js | 6090 +- .../thirdparty/cometd/cometd/AckExtension.js | 224 +- .../thirdparty/cometd/cometd/ReloadExtension.js | 468 +- .../thirdparty/cometd/cometd/TimeStampExtension.js | 84 +- .../thirdparty/cometd/cometd/TimeSyncExtension.js | 432 +- .../thirdparty/cometd/jquery/jquery.cometd-ack.js | 68 +- .../cometd/jquery/jquery.cometd-reload.js | 84 +- .../cometd/jquery/jquery.cometd-timestamp.js | 68 +- .../cometd/jquery/jquery.cometd-timesync.js | 68 +- .../thirdparty/cometd/jquery/jquery.cometd.js | 278 +- .../common/thirdparty/data-tables/DT_bootstrap.css | 478 +- .../common/thirdparty/data-tables/DT_bootstrap.js | 724 +- .../common/thirdparty/data-tables/DataTableICT.js | 2918 +- .../thirdparty/data-tables/DataTableSmartClient.js | 2430 +- .../data-tables/DataTableSmartClientApp.js | 2624 +- .../data-tables/app-test-i18n-datatable-zh-CN.json | 100 +- .../app-universal-i18n-datatable-en-US.json | 176 +- .../app-universal-i18n-datatable-zh-CN.json | 180 +- .../common/thirdparty/data-tables/dataTable.html | 310 +- .../data-tables/dataTables.bootstrap.css | 662 +- .../data-tables/jquery.dataTables-1.9.4.js | 24202 ++-- .../data-tables/jquery.dataTables-1.9.4.min.js | 310 +- .../thirdparty/data-tables/jquery.dataTables.js | 30536 ++--- .../data-tables/jquery.dataTables.min.js | 332 +- .../thirdparty/data-tables/style-datatable.css | 306 +- .../common/thirdparty/echarts/echarts-all.js | 98 +- .../webapp/common/thirdparty/echarts/echarts.js | 109002 +++++++++--------- .../common/thirdparty/fakeLoader/fakeLoader.css | 762 +- .../common/thirdparty/fakeLoader/fakeLoader.min.js | 348 +- .../thirdparty/font-awesome/css/font-awesome.css | 3344 +- .../font-awesome/css/font-awesome.min.css | 6 +- .../font-awesome/fonts/fontawesome-webfont.svg | 1038 +- .../font-awesome/less/bordered-pulled.less | 32 +- .../common/thirdparty/font-awesome/less/core.less | 22 +- .../thirdparty/font-awesome/less/fixed-width.less | 12 +- .../thirdparty/font-awesome/less/font-awesome.less | 34 +- .../common/thirdparty/font-awesome/less/icons.less | 1104 +- .../thirdparty/font-awesome/less/larger.less | 26 +- .../common/thirdparty/font-awesome/less/list.less | 38 +- .../thirdparty/font-awesome/less/mixins.less | 50 +- .../common/thirdparty/font-awesome/less/path.less | 28 +- .../font-awesome/less/rotated-flipped.less | 40 +- .../thirdparty/font-awesome/less/spinning.less | 58 +- .../thirdparty/font-awesome/less/stacked.less | 40 +- .../thirdparty/font-awesome/less/variables.less | 1122 +- .../font-awesome/scss/_bordered-pulled.scss | 32 +- .../common/thirdparty/font-awesome/scss/_core.scss | 22 +- .../thirdparty/font-awesome/scss/_fixed-width.scss | 12 +- .../thirdparty/font-awesome/scss/_icons.scss | 1104 +- .../thirdparty/font-awesome/scss/_larger.scss | 26 +- .../common/thirdparty/font-awesome/scss/_list.scss | 38 +- .../thirdparty/font-awesome/scss/_mixins.scss | 50 +- .../common/thirdparty/font-awesome/scss/_path.scss | 28 +- .../font-awesome/scss/_rotated-flipped.scss | 40 +- .../thirdparty/font-awesome/scss/_spinning.scss | 58 +- .../thirdparty/font-awesome/scss/_stacked.scss | 40 +- .../thirdparty/font-awesome/scss/_variables.scss | 1122 +- .../thirdparty/font-awesome/scss/font-awesome.scss | 34 +- .../webapp/common/thirdparty/freewall/freewall.js | 2612 +- .../webapp/common/thirdparty/icheck/bower.json | 84 +- .../thirdparty/icheck/demo/css/montserrat-bold.svg | 2978 +- .../icheck/demo/css/montserrat-regular.svg | 2728 +- .../thirdparty/icheck/demo/css/normalize.css | 1054 +- .../common/thirdparty/icheck/demo/js/custom.js | 216 +- .../common/thirdparty/icheck/demo/js/custom.min.js | 8 +- .../common/thirdparty/icheck/demo/js/jquery.js | 6 +- .../common/thirdparty/icheck/icheck.jquery.json | 96 +- .../main/webapp/common/thirdparty/icheck/icheck.js | 1018 +- .../webapp/common/thirdparty/icheck/icheck.min.js | 22 +- .../webapp/common/thirdparty/icheck/skins/all.css | 120 +- .../common/thirdparty/icheck/skins/flat/_all.css | 1058 +- .../common/thirdparty/icheck/skins/flat/aero.css | 104 +- .../common/thirdparty/icheck/skins/flat/blue.css | 104 +- .../common/thirdparty/icheck/skins/flat/flat.css | 104 +- .../common/thirdparty/icheck/skins/flat/green.css | 104 +- .../common/thirdparty/icheck/skins/flat/grey.css | 104 +- .../common/thirdparty/icheck/skins/flat/orange.css | 104 +- .../common/thirdparty/icheck/skins/flat/pink.css | 104 +- .../common/thirdparty/icheck/skins/flat/purple.css | 104 +- .../common/thirdparty/icheck/skins/flat/red.css | 104 +- .../common/thirdparty/icheck/skins/flat/yellow.css | 104 +- .../thirdparty/icheck/skins/futurico/futurico.css | 104 +- .../common/thirdparty/icheck/skins/line/aero.css | 140 +- .../common/thirdparty/icheck/skins/line/blue.css | 140 +- .../common/thirdparty/icheck/skins/line/green.css | 140 +- .../common/thirdparty/icheck/skins/line/grey.css | 140 +- .../common/thirdparty/icheck/skins/line/line.css | 140 +- .../common/thirdparty/icheck/skins/line/orange.css | 140 +- .../common/thirdparty/icheck/skins/line/pink.css | 140 +- .../common/thirdparty/icheck/skins/line/purple.css | 140 +- .../common/thirdparty/icheck/skins/line/red.css | 140 +- .../common/thirdparty/icheck/skins/line/yellow.css | 140 +- .../thirdparty/icheck/skins/minimal/_all.css | 1178 +- .../thirdparty/icheck/skins/minimal/aero.css | 116 +- .../thirdparty/icheck/skins/minimal/blue.css | 116 +- .../thirdparty/icheck/skins/minimal/green.css | 116 +- .../thirdparty/icheck/skins/minimal/grey.css | 116 +- .../thirdparty/icheck/skins/minimal/minimal.css | 116 +- .../thirdparty/icheck/skins/minimal/orange.css | 116 +- .../thirdparty/icheck/skins/minimal/pink.css | 116 +- .../thirdparty/icheck/skins/minimal/purple.css | 116 +- .../common/thirdparty/icheck/skins/minimal/red.css | 116 +- .../thirdparty/icheck/skins/minimal/yellow.css | 116 +- .../thirdparty/icheck/skins/polaris/polaris.css | 116 +- .../common/thirdparty/icheck/skins/square/_all.css | 1178 +- .../common/thirdparty/icheck/skins/square/aero.css | 116 +- .../common/thirdparty/icheck/skins/square/blue.css | 116 +- .../thirdparty/icheck/skins/square/green.css | 116 +- .../common/thirdparty/icheck/skins/square/grey.css | 116 +- .../thirdparty/icheck/skins/square/orange.css | 116 +- .../common/thirdparty/icheck/skins/square/pink.css | 116 +- .../thirdparty/icheck/skins/square/purple.css | 116 +- .../common/thirdparty/icheck/skins/square/red.css | 116 +- .../thirdparty/icheck/skins/square/square.css | 116 +- .../thirdparty/icheck/skins/square/yellow.css | 116 +- .../thirdparty/jQuery UI/jquery-ui-1.12.1.min.css | 12 +- .../thirdparty/jQuery UI/jquery-ui-1.12.1.min.js | 24 +- .../jQuery-File-Upload/css/jquery.fileupload.css | 74 +- .../jQuery-File-Upload/js/jquery.fileupload.js | 2954 +- .../js/jquery.iframe-transport.js | 434 +- .../js/vendor/jquery.ui.widget.js | 1144 +- .../jquery-blockui/jquery.blockui.min.js | 28 +- .../thirdparty/jquery-cokie/jquery.cokie.min.js | 16 +- .../common/thirdparty/jquery-validation/README.md | 144 +- .../jquery-validation/dist/additional-methods.js | 1234 +- .../dist/additional-methods.min.js | 20 +- .../jquery-validation/dist/jquery.validate.js | 2462 +- .../jquery-validation/dist/jquery.validate.min.js | 22 +- .../jquery-validation/js/additional-methods.js | 1854 +- .../jquery-validation/js/additional-methods.min.js | 6 +- .../jquery-validation/js/jquery.validate.js | 2712 +- .../jquery-validation/js/jquery.validate.min.js | 6 +- .../js/localization/messages_ar.js | 64 +- .../js/localization/messages_ar.min.js | 6 +- .../js/localization/messages_bg.js | 64 +- .../js/localization/messages_bg.min.js | 6 +- .../js/localization/messages_ca.js | 64 +- .../js/localization/messages_ca.min.js | 6 +- .../js/localization/messages_cs.js | 64 +- .../js/localization/messages_cs.min.js | 6 +- .../js/localization/messages_da.js | 58 +- .../js/localization/messages_da.min.js | 6 +- .../js/localization/messages_de.js | 58 +- .../js/localization/messages_de.min.js | 6 +- .../js/localization/messages_el.js | 64 +- .../js/localization/messages_el.min.js | 6 +- .../js/localization/messages_es.js | 70 +- .../js/localization/messages_es.min.js | 6 +- .../js/localization/messages_es_AR.js | 72 +- .../js/localization/messages_es_AR.min.js | 6 +- .../js/localization/messages_et.js | 60 +- .../js/localization/messages_et.min.js | 6 +- .../js/localization/messages_eu.js | 64 +- .../js/localization/messages_eu.min.js | 6 +- .../js/localization/messages_fa.js | 70 +- .../js/localization/messages_fa.min.js | 6 +- .../js/localization/messages_fi.js | 60 +- .../js/localization/messages_fi.min.js | 6 +- .../js/localization/messages_fr.js | 116 +- .../js/localization/messages_fr.min.js | 6 +- .../js/localization/messages_gl.js | 74 +- .../js/localization/messages_gl.min.js | 6 +- .../js/localization/messages_he.js | 64 +- .../js/localization/messages_he.min.js | 6 +- .../js/localization/messages_hr.js | 64 +- .../js/localization/messages_hr.min.js | 6 +- .../js/localization/messages_hu.js | 62 +- .../js/localization/messages_hu.min.js | 6 +- .../js/localization/messages_id.js | 62 +- .../js/localization/messages_id.min.js | 6 +- .../js/localization/messages_is.js | 60 +- .../js/localization/messages_is.min.js | 6 +- .../js/localization/messages_it.js | 70 +- .../js/localization/messages_it.min.js | 6 +- .../js/localization/messages_ja.js | 64 +- .../js/localization/messages_ja.min.js | 6 +- .../js/localization/messages_ka.js | 64 +- .../js/localization/messages_ka.min.js | 6 +- .../js/localization/messages_kk.js | 64 +- .../js/localization/messages_kk.min.js | 6 +- .../js/localization/messages_ko.js | 64 +- .../js/localization/messages_ko.min.js | 6 +- .../js/localization/messages_lt.js | 64 +- .../js/localization/messages_lt.min.js | 6 +- .../js/localization/messages_lv.js | 64 +- .../js/localization/messages_lv.min.js | 6 +- .../js/localization/messages_my.js | 64 +- .../js/localization/messages_my.min.js | 6 +- .../js/localization/messages_nl.js | 84 +- .../js/localization/messages_nl.min.js | 6 +- .../js/localization/messages_no.js | 64 +- .../js/localization/messages_no.min.js | 6 +- .../js/localization/messages_pl.js | 64 +- .../js/localization/messages_pl.min.js | 6 +- .../js/localization/messages_pt_BR.js | 72 +- .../js/localization/messages_pt_BR.min.js | 6 +- .../js/localization/messages_pt_PT.js | 72 +- .../js/localization/messages_pt_PT.min.js | 6 +- .../js/localization/messages_ro.js | 64 +- .../js/localization/messages_ro.min.js | 6 +- .../js/localization/messages_ru.js | 64 +- .../js/localization/messages_ru.min.js | 6 +- .../js/localization/messages_si.js | 64 +- .../js/localization/messages_si.min.js | 6 +- .../js/localization/messages_sk.js | 58 +- .../js/localization/messages_sk.min.js | 6 +- .../js/localization/messages_sl.js | 64 +- .../js/localization/messages_sl.min.js | 6 +- .../js/localization/messages_sr.js | 64 +- .../js/localization/messages_sr.min.js | 6 +- .../js/localization/messages_sr_lat.js | 64 +- .../js/localization/messages_sr_lat.min.js | 6 +- .../js/localization/messages_sv.js | 60 +- .../js/localization/messages_sv.min.js | 6 +- .../js/localization/messages_th.js | 64 +- .../js/localization/messages_th.min.js | 6 +- .../js/localization/messages_tj.js | 64 +- .../js/localization/messages_tj.min.js | 6 +- .../js/localization/messages_tr.js | 64 +- .../js/localization/messages_tr.min.js | 6 +- .../js/localization/messages_uk.js | 64 +- .../js/localization/messages_uk.min.js | 6 +- .../js/localization/messages_vi.js | 64 +- .../js/localization/messages_vi.min.js | 6 +- .../js/localization/messages_zh.js | 64 +- .../js/localization/messages_zh.min.js | 6 +- .../js/localization/messages_zh_TW.js | 66 +- .../js/localization/messages_zh_TW.min.js | 6 +- .../js/localization/methods_de.js | 42 +- .../js/localization/methods_de.min.js | 6 +- .../js/localization/methods_es_CL.js | 42 +- .../js/localization/methods_es_CL.min.js | 6 +- .../js/localization/methods_fi.js | 42 +- .../js/localization/methods_fi.min.js | 6 +- .../js/localization/methods_nl.js | 36 +- .../js/localization/methods_nl.min.js | 6 +- .../js/localization/methods_pt.js | 36 +- .../js/localization/methods_pt.min.js | 6 +- .../jquery.i18n/jquery.i18n.properties-1.0.9.js | 956 +- .../common/thirdparty/jquery/jquery-1.10.2.min.js | 8 +- .../common/thirdparty/jquery/jquery-1.11.2.js | 20692 ++-- .../common/thirdparty/jquery/jquery-1.11.2.min.js | 8 +- .../common/thirdparty/jquery/jquery-1.4.4.min.js | 332 +- .../common/thirdparty/jquery/jquery-2.1.3.js | 18410 +-- .../common/thirdparty/jquery/jquery-2.1.3.min.js | 8 +- .../thirdparty/jquery/jquery-migrate-1.2.1.js | 1042 +- .../thirdparty/jquery/jquery-migrate-1.2.1.min.js | 2 +- .../common/thirdparty/jquery/jquery.reveal.js | 304 +- .../common/thirdparty/select2/select2-custom.css | 468 +- .../webapp/common/thirdparty/select2/select2.css | 1214 +- .../common/thirdparty/select2/select2.min.js | 42 +- .../webapp/common/thirdparty/sigma/sigma.min.js | 8 +- .../sigma/sigma.renderers.customShapes.min.js | 2 +- .../sigma/sigma.renderers.edgeLabels.min.js | 2 +- .../webapp/common/thirdparty/uniform/README.md | 778 +- .../thirdparty/uniform/css/uniform.default.css | 732 +- .../thirdparty/uniform/css/uniform.default.min.css | 2 +- .../thirdparty/uniform/css/uniform.default.scss | 300 +- .../common/thirdparty/uniform/jquery.uniform.js | 2136 +- .../webapp/common/thirdparty/zTree/api/API_cn.html | 204 +- .../webapp/common/thirdparty/zTree/api/API_en.html | 202 +- .../common/thirdparty/zTree/api/apiCss/api.js | 1182 +- .../common/thirdparty/zTree/api/apiCss/common.css | 436 +- .../thirdparty/zTree/api/apiCss/common_ie6.css | 44 +- .../zTree/api/apiCss/jquery-1.6.2.min.js | 34 +- .../zTree/api/apiCss/jquery.ztree.core-3.5.js | 138 +- .../zTree/api/apiCss/zTreeStyleForApi.css | 98 +- .../thirdparty/zTree/api/cn/fn.zTree._z.html | 24 +- .../thirdparty/zTree/api/cn/fn.zTree.destroy.html | 54 +- .../zTree/api/cn/fn.zTree.getZTreeObj.html | 46 +- .../thirdparty/zTree/api/cn/fn.zTree.init.html | 146 +- .../zTree/api/cn/setting.async.autoParam.html | 76 +- .../zTree/api/cn/setting.async.contentType.html | 56 +- .../zTree/api/cn/setting.async.dataFilter.html | 88 +- .../zTree/api/cn/setting.async.dataType.html | 56 +- .../zTree/api/cn/setting.async.enable.html | 58 +- .../zTree/api/cn/setting.async.otherParam.html | 78 +- .../zTree/api/cn/setting.async.type.html | 58 +- .../thirdparty/zTree/api/cn/setting.async.url.html | 98 +- .../zTree/api/cn/setting.callback.beforeAsync.html | 68 +- .../zTree/api/cn/setting.callback.beforeCheck.html | 66 +- .../zTree/api/cn/setting.callback.beforeClick.html | 96 +- .../api/cn/setting.callback.beforeCollapse.html | 66 +- .../api/cn/setting.callback.beforeDblClick.html | 70 +- .../zTree/api/cn/setting.callback.beforeDrag.html | 76 +- .../api/cn/setting.callback.beforeDragOpen.html | 72 +- .../zTree/api/cn/setting.callback.beforeDrop.html | 94 +- .../api/cn/setting.callback.beforeEditName.html | 74 +- .../api/cn/setting.callback.beforeExpand.html | 66 +- .../api/cn/setting.callback.beforeMouseDown.html | 68 +- .../api/cn/setting.callback.beforeMouseUp.html | 68 +- .../api/cn/setting.callback.beforeRemove.html | 72 +- .../api/cn/setting.callback.beforeRename.html | 90 +- .../api/cn/setting.callback.beforeRightClick.html | 68 +- .../api/cn/setting.callback.onAsyncError.html | 82 +- .../api/cn/setting.callback.onAsyncSuccess.html | 74 +- .../zTree/api/cn/setting.callback.onCheck.html | 66 +- .../zTree/api/cn/setting.callback.onClick.html | 96 +- .../zTree/api/cn/setting.callback.onCollapse.html | 66 +- .../zTree/api/cn/setting.callback.onDblClick.html | 68 +- .../zTree/api/cn/setting.callback.onDrag.html | 66 +- .../zTree/api/cn/setting.callback.onDragMove.html | 66 +- .../zTree/api/cn/setting.callback.onDrop.html | 90 +- .../zTree/api/cn/setting.callback.onExpand.html | 66 +- .../zTree/api/cn/setting.callback.onMouseDown.html | 68 +- .../zTree/api/cn/setting.callback.onMouseUp.html | 68 +- .../api/cn/setting.callback.onNodeCreated.html | 68 +- .../zTree/api/cn/setting.callback.onRemove.html | 66 +- .../zTree/api/cn/setting.callback.onRename.html | 78 +- .../api/cn/setting.callback.onRightClick.html | 70 +- .../api/cn/setting.check.autoCheckTrigger.html | 54 +- .../api/cn/setting.check.chkDisabledInherit.html | 54 +- .../zTree/api/cn/setting.check.chkStyle.html | 94 +- .../zTree/api/cn/setting.check.chkboxType.html | 60 +- .../zTree/api/cn/setting.check.enable.html | 48 +- .../zTree/api/cn/setting.check.nocheckInherit.html | 54 +- .../zTree/api/cn/setting.check.radioType.html | 56 +- .../zTree/api/cn/setting.data.keep.leaf.html | 54 +- .../zTree/api/cn/setting.data.keep.parent.html | 54 +- .../zTree/api/cn/setting.data.key.checked.html | 46 +- .../zTree/api/cn/setting.data.key.children.html | 44 +- .../zTree/api/cn/setting.data.key.name.html | 44 +- .../zTree/api/cn/setting.data.key.title.html | 46 +- .../zTree/api/cn/setting.data.key.url.html | 46 +- .../api/cn/setting.data.simpleData.enable.html | 74 +- .../api/cn/setting.data.simpleData.idKey.html | 62 +- .../api/cn/setting.data.simpleData.pIdKey.html | 62 +- .../api/cn/setting.data.simpleData.rootPId.html | 62 +- .../cn/setting.edit.drag.autoExpandTrigger.html | 54 +- .../api/cn/setting.edit.drag.autoOpenTime.html | 48 +- .../zTree/api/cn/setting.edit.drag.borderMax.html | 48 +- .../zTree/api/cn/setting.edit.drag.borderMin.html | 48 +- .../zTree/api/cn/setting.edit.drag.inner.html | 116 +- .../zTree/api/cn/setting.edit.drag.isCopy.html | 62 +- .../zTree/api/cn/setting.edit.drag.isMove.html | 62 +- .../api/cn/setting.edit.drag.maxShowNodeNum.html | 48 +- .../api/cn/setting.edit.drag.minMoveSize.html | 48 +- .../zTree/api/cn/setting.edit.drag.next.html | 114 +- .../zTree/api/cn/setting.edit.drag.prev.html | 114 +- .../api/cn/setting.edit.editNameSelectAll.html | 52 +- .../zTree/api/cn/setting.edit.enable.html | 74 +- .../zTree/api/cn/setting.edit.removeTitle.html | 94 +- .../zTree/api/cn/setting.edit.renameTitle.html | 94 +- .../zTree/api/cn/setting.edit.showRemoveBtn.html | 96 +- .../zTree/api/cn/setting.edit.showRenameBtn.html | 100 +- .../thirdparty/zTree/api/cn/setting.treeId.html | 26 +- .../thirdparty/zTree/api/cn/setting.treeObj.html | 26 +- .../zTree/api/cn/setting.view.addDiyDom.html | 78 +- .../zTree/api/cn/setting.view.addHoverDom.html | 88 +- .../api/cn/setting.view.autoCancelSelected.html | 50 +- .../zTree/api/cn/setting.view.dblClickExpand.html | 86 +- .../zTree/api/cn/setting.view.expandSpeed.html | 60 +- .../zTree/api/cn/setting.view.fontCss.html | 82 +- .../zTree/api/cn/setting.view.nameIsHTML.html | 52 +- .../zTree/api/cn/setting.view.removeHoverDom.html | 88 +- .../zTree/api/cn/setting.view.selectedMulti.html | 52 +- .../zTree/api/cn/setting.view.showIcon.html | 86 +- .../zTree/api/cn/setting.view.showLine.html | 48 +- .../zTree/api/cn/setting.view.showTitle.html | 90 +- .../api/cn/setting.view.txtSelectedEnable.html | 48 +- .../zTree/api/cn/treeNode.check_Child_State.html | 84 +- .../zTree/api/cn/treeNode.check_Focus.html | 36 +- .../thirdparty/zTree/api/cn/treeNode.checked.html | 62 +- .../zTree/api/cn/treeNode.checkedOld.html | 48 +- .../thirdparty/zTree/api/cn/treeNode.children.html | 68 +- .../zTree/api/cn/treeNode.chkDisabled.html | 54 +- .../thirdparty/zTree/api/cn/treeNode.click.html | 46 +- .../thirdparty/zTree/api/cn/treeNode.diy.html | 28 +- .../zTree/api/cn/treeNode.editNameFlag.html | 36 +- .../zTree/api/cn/treeNode.getCheckStatus.html | 124 +- .../zTree/api/cn/treeNode.getNextNode.html | 52 +- .../zTree/api/cn/treeNode.getParentNode.html | 52 +- .../zTree/api/cn/treeNode.getPreNode.html | 52 +- .../zTree/api/cn/treeNode.halfCheck.html | 56 +- .../thirdparty/zTree/api/cn/treeNode.icon.html | 64 +- .../zTree/api/cn/treeNode.iconClose.html | 64 +- .../thirdparty/zTree/api/cn/treeNode.iconOpen.html | 64 +- .../thirdparty/zTree/api/cn/treeNode.iconSkin.html | 84 +- .../zTree/api/cn/treeNode.isAjaxing.html | 50 +- .../zTree/api/cn/treeNode.isFirstNode.html | 54 +- .../thirdparty/zTree/api/cn/treeNode.isHidden.html | 52 +- .../thirdparty/zTree/api/cn/treeNode.isHover.html | 36 +- .../zTree/api/cn/treeNode.isLastNode.html | 54 +- .../thirdparty/zTree/api/cn/treeNode.isParent.html | 54 +- .../thirdparty/zTree/api/cn/treeNode.level.html | 48 +- .../thirdparty/zTree/api/cn/treeNode.name.html | 48 +- .../thirdparty/zTree/api/cn/treeNode.nocheck.html | 50 +- .../thirdparty/zTree/api/cn/treeNode.open.html | 58 +- .../zTree/api/cn/treeNode.parentTId.html | 52 +- .../thirdparty/zTree/api/cn/treeNode.tId.html | 48 +- .../thirdparty/zTree/api/cn/treeNode.target.html | 46 +- .../thirdparty/zTree/api/cn/treeNode.url.html | 48 +- .../thirdparty/zTree/api/cn/treeNode.zAsync.html | 54 +- .../thirdparty/zTree/api/cn/zTreeObj.addNodes.html | 82 +- .../zTree/api/cn/zTreeObj.cancelEditName.html | 58 +- .../zTree/api/cn/zTreeObj.cancelSelectedNode.html | 68 +- .../zTree/api/cn/zTreeObj.checkAllNodes.html | 56 +- .../zTree/api/cn/zTreeObj.checkNode.html | 86 +- .../thirdparty/zTree/api/cn/zTreeObj.copyNode.html | 86 +- .../thirdparty/zTree/api/cn/zTreeObj.destroy.html | 48 +- .../thirdparty/zTree/api/cn/zTreeObj.editName.html | 56 +- .../zTree/api/cn/zTreeObj.expandAll.html | 58 +- .../zTree/api/cn/zTreeObj.expandNode.html | 98 +- .../api/cn/zTreeObj.getChangeCheckedNodes.html | 46 +- .../zTree/api/cn/zTreeObj.getCheckedNodes.html | 54 +- .../zTree/api/cn/zTreeObj.getNodeByParam.html | 62 +- .../zTree/api/cn/zTreeObj.getNodeByTId.html | 52 +- .../zTree/api/cn/zTreeObj.getNodeIndex.html | 58 +- .../thirdparty/zTree/api/cn/zTreeObj.getNodes.html | 50 +- .../zTree/api/cn/zTreeObj.getNodesByFilter.html | 84 +- .../zTree/api/cn/zTreeObj.getNodesByParam.html | 60 +- .../api/cn/zTreeObj.getNodesByParamFuzzy.html | 62 +- .../zTree/api/cn/zTreeObj.getSelectedNodes.html | 44 +- .../thirdparty/zTree/api/cn/zTreeObj.hideNode.html | 56 +- .../zTree/api/cn/zTreeObj.hideNodes.html | 56 +- .../thirdparty/zTree/api/cn/zTreeObj.moveNode.html | 90 +- .../zTree/api/cn/zTreeObj.reAsyncChildNodes.html | 82 +- .../thirdparty/zTree/api/cn/zTreeObj.refresh.html | 46 +- .../zTree/api/cn/zTreeObj.removeChildNodes.html | 62 +- .../zTree/api/cn/zTreeObj.removeNode.html | 66 +- .../zTree/api/cn/zTreeObj.selectNode.html | 66 +- .../zTree/api/cn/zTreeObj.setChkDisabled.html | 86 +- .../zTree/api/cn/zTreeObj.setEditable.html | 52 +- .../thirdparty/zTree/api/cn/zTreeObj.setting.html | 24 +- .../thirdparty/zTree/api/cn/zTreeObj.showNode.html | 60 +- .../zTree/api/cn/zTreeObj.showNodes.html | 56 +- .../zTree/api/cn/zTreeObj.transformToArray.html | 48 +- .../api/cn/zTreeObj.transformTozTreeNodes.html | 84 +- .../zTree/api/cn/zTreeObj.updateNode.html | 72 +- .../thirdparty/zTree/api/en/fn.zTree._z.html | 24 +- .../thirdparty/zTree/api/en/fn.zTree.destroy.html | 54 +- .../zTree/api/en/fn.zTree.getZTreeObj.html | 48 +- .../thirdparty/zTree/api/en/fn.zTree.init.html | 148 +- .../zTree/api/en/setting.async.autoParam.html | 76 +- .../zTree/api/en/setting.async.contentType.html | 56 +- .../zTree/api/en/setting.async.dataFilter.html | 88 +- .../zTree/api/en/setting.async.dataType.html | 56 +- .../zTree/api/en/setting.async.enable.html | 58 +- .../zTree/api/en/setting.async.otherParam.html | 78 +- .../zTree/api/en/setting.async.type.html | 58 +- .../thirdparty/zTree/api/en/setting.async.url.html | 98 +- .../zTree/api/en/setting.callback.beforeAsync.html | 68 +- .../zTree/api/en/setting.callback.beforeCheck.html | 66 +- .../zTree/api/en/setting.callback.beforeClick.html | 96 +- .../api/en/setting.callback.beforeCollapse.html | 66 +- .../api/en/setting.callback.beforeDblClick.html | 70 +- .../zTree/api/en/setting.callback.beforeDrag.html | 76 +- .../api/en/setting.callback.beforeDragOpen.html | 72 +- .../zTree/api/en/setting.callback.beforeDrop.html | 98 +- .../api/en/setting.callback.beforeEditName.html | 74 +- .../api/en/setting.callback.beforeExpand.html | 66 +- .../api/en/setting.callback.beforeMouseDown.html | 68 +- .../api/en/setting.callback.beforeMouseUp.html | 68 +- .../api/en/setting.callback.beforeRemove.html | 72 +- .../api/en/setting.callback.beforeRename.html | 90 +- .../api/en/setting.callback.beforeRightClick.html | 68 +- .../api/en/setting.callback.onAsyncError.html | 82 +- .../api/en/setting.callback.onAsyncSuccess.html | 74 +- .../zTree/api/en/setting.callback.onCheck.html | 66 +- .../zTree/api/en/setting.callback.onClick.html | 96 +- .../zTree/api/en/setting.callback.onCollapse.html | 66 +- .../zTree/api/en/setting.callback.onDblClick.html | 68 +- .../zTree/api/en/setting.callback.onDrag.html | 66 +- .../zTree/api/en/setting.callback.onDragMove.html | 66 +- .../zTree/api/en/setting.callback.onDrop.html | 94 +- .../zTree/api/en/setting.callback.onExpand.html | 66 +- .../zTree/api/en/setting.callback.onMouseDown.html | 68 +- .../zTree/api/en/setting.callback.onMouseUp.html | 68 +- .../api/en/setting.callback.onNodeCreated.html | 68 +- .../zTree/api/en/setting.callback.onRemove.html | 66 +- .../zTree/api/en/setting.callback.onRename.html | 78 +- .../api/en/setting.callback.onRightClick.html | 70 +- .../api/en/setting.check.autoCheckTrigger.html | 56 +- .../api/en/setting.check.chkDisabledInherit.html | 54 +- .../zTree/api/en/setting.check.chkStyle.html | 94 +- .../zTree/api/en/setting.check.chkboxType.html | 60 +- .../zTree/api/en/setting.check.enable.html | 50 +- .../zTree/api/en/setting.check.nocheckInherit.html | 54 +- .../zTree/api/en/setting.check.radioType.html | 56 +- .../zTree/api/en/setting.data.keep.leaf.html | 54 +- .../zTree/api/en/setting.data.keep.parent.html | 54 +- .../zTree/api/en/setting.data.key.checked.html | 46 +- .../zTree/api/en/setting.data.key.children.html | 44 +- .../zTree/api/en/setting.data.key.name.html | 44 +- .../zTree/api/en/setting.data.key.title.html | 46 +- .../zTree/api/en/setting.data.key.url.html | 46 +- .../api/en/setting.data.simpleData.enable.html | 76 +- .../api/en/setting.data.simpleData.idKey.html | 62 +- .../api/en/setting.data.simpleData.pIdKey.html | 62 +- .../api/en/setting.data.simpleData.rootPId.html | 62 +- .../en/setting.edit.drag.autoExpandTrigger.html | 56 +- .../api/en/setting.edit.drag.autoOpenTime.html | 48 +- .../zTree/api/en/setting.edit.drag.borderMax.html | 48 +- .../zTree/api/en/setting.edit.drag.borderMin.html | 48 +- .../zTree/api/en/setting.edit.drag.inner.html | 118 +- .../zTree/api/en/setting.edit.drag.isCopy.html | 62 +- .../zTree/api/en/setting.edit.drag.isMove.html | 62 +- .../api/en/setting.edit.drag.maxShowNodeNum.html | 48 +- .../api/en/setting.edit.drag.minMoveSize.html | 48 +- .../zTree/api/en/setting.edit.drag.next.html | 116 +- .../zTree/api/en/setting.edit.drag.prev.html | 116 +- .../api/en/setting.edit.editNameSelectAll.html | 52 +- .../zTree/api/en/setting.edit.enable.html | 76 +- .../zTree/api/en/setting.edit.removeTitle.html | 94 +- .../zTree/api/en/setting.edit.renameTitle.html | 94 +- .../zTree/api/en/setting.edit.showRemoveBtn.html | 98 +- .../zTree/api/en/setting.edit.showRenameBtn.html | 102 +- .../thirdparty/zTree/api/en/setting.treeId.html | 26 +- .../thirdparty/zTree/api/en/setting.treeObj.html | 26 +- .../zTree/api/en/setting.view.addDiyDom.html | 78 +- .../zTree/api/en/setting.view.addHoverDom.html | 88 +- .../api/en/setting.view.autoCancelSelected.html | 52 +- .../zTree/api/en/setting.view.dblClickExpand.html | 88 +- .../zTree/api/en/setting.view.expandSpeed.html | 60 +- .../zTree/api/en/setting.view.fontCss.html | 82 +- .../zTree/api/en/setting.view.nameIsHTML.html | 54 +- .../zTree/api/en/setting.view.removeHoverDom.html | 88 +- .../zTree/api/en/setting.view.selectedMulti.html | 54 +- .../zTree/api/en/setting.view.showIcon.html | 88 +- .../zTree/api/en/setting.view.showLine.html | 50 +- .../zTree/api/en/setting.view.showTitle.html | 92 +- .../api/en/setting.view.txtSelectedEnable.html | 50 +- .../zTree/api/en/treeNode.check_Child_State.html | 84 +- .../zTree/api/en/treeNode.check_Focus.html | 36 +- .../thirdparty/zTree/api/en/treeNode.checked.html | 62 +- .../zTree/api/en/treeNode.checkedOld.html | 48 +- .../thirdparty/zTree/api/en/treeNode.children.html | 68 +- .../zTree/api/en/treeNode.chkDisabled.html | 54 +- .../thirdparty/zTree/api/en/treeNode.click.html | 46 +- .../thirdparty/zTree/api/en/treeNode.diy.html | 28 +- .../zTree/api/en/treeNode.editNameFlag.html | 36 +- .../zTree/api/en/treeNode.getCheckStatus.html | 124 +- .../zTree/api/en/treeNode.getNextNode.html | 52 +- .../zTree/api/en/treeNode.getParentNode.html | 52 +- .../zTree/api/en/treeNode.getPreNode.html | 52 +- .../zTree/api/en/treeNode.halfCheck.html | 56 +- .../thirdparty/zTree/api/en/treeNode.icon.html | 64 +- .../zTree/api/en/treeNode.iconClose.html | 64 +- .../thirdparty/zTree/api/en/treeNode.iconOpen.html | 64 +- .../thirdparty/zTree/api/en/treeNode.iconSkin.html | 84 +- .../zTree/api/en/treeNode.isAjaxing.html | 50 +- .../zTree/api/en/treeNode.isFirstNode.html | 54 +- .../thirdparty/zTree/api/en/treeNode.isHidden.html | 54 +- .../thirdparty/zTree/api/en/treeNode.isHover.html | 36 +- .../zTree/api/en/treeNode.isLastNode.html | 54 +- .../thirdparty/zTree/api/en/treeNode.isParent.html | 54 +- .../thirdparty/zTree/api/en/treeNode.level.html | 48 +- .../thirdparty/zTree/api/en/treeNode.name.html | 48 +- .../thirdparty/zTree/api/en/treeNode.nocheck.html | 50 +- .../thirdparty/zTree/api/en/treeNode.open.html | 58 +- .../zTree/api/en/treeNode.parentTId.html | 52 +- .../thirdparty/zTree/api/en/treeNode.tId.html | 48 +- .../thirdparty/zTree/api/en/treeNode.target.html | 46 +- .../thirdparty/zTree/api/en/treeNode.url.html | 48 +- .../thirdparty/zTree/api/en/treeNode.zAsync.html | 54 +- .../thirdparty/zTree/api/en/zTreeObj.addNodes.html | 82 +- .../zTree/api/en/zTreeObj.cancelEditName.html | 58 +- .../zTree/api/en/zTreeObj.cancelSelectedNode.html | 68 +- .../zTree/api/en/zTreeObj.checkAllNodes.html | 56 +- .../zTree/api/en/zTreeObj.checkNode.html | 86 +- .../thirdparty/zTree/api/en/zTreeObj.copyNode.html | 92 +- .../thirdparty/zTree/api/en/zTreeObj.destroy.html | 48 +- .../thirdparty/zTree/api/en/zTreeObj.editName.html | 56 +- .../zTree/api/en/zTreeObj.expandAll.html | 58 +- .../zTree/api/en/zTreeObj.expandNode.html | 98 +- .../api/en/zTreeObj.getChangeCheckedNodes.html | 46 +- .../zTree/api/en/zTreeObj.getCheckedNodes.html | 54 +- .../zTree/api/en/zTreeObj.getNodeByParam.html | 62 +- .../zTree/api/en/zTreeObj.getNodeByTId.html | 52 +- .../zTree/api/en/zTreeObj.getNodeIndex.html | 58 +- .../thirdparty/zTree/api/en/zTreeObj.getNodes.html | 50 +- .../zTree/api/en/zTreeObj.getNodesByFilter.html | 84 +- .../zTree/api/en/zTreeObj.getNodesByParam.html | 60 +- .../api/en/zTreeObj.getNodesByParamFuzzy.html | 62 +- .../zTree/api/en/zTreeObj.getSelectedNodes.html | 44 +- .../thirdparty/zTree/api/en/zTreeObj.hideNode.html | 56 +- .../zTree/api/en/zTreeObj.hideNodes.html | 56 +- .../thirdparty/zTree/api/en/zTreeObj.moveNode.html | 96 +- .../zTree/api/en/zTreeObj.reAsyncChildNodes.html | 82 +- .../thirdparty/zTree/api/en/zTreeObj.refresh.html | 46 +- .../zTree/api/en/zTreeObj.removeChildNodes.html | 62 +- .../zTree/api/en/zTreeObj.removeNode.html | 66 +- .../zTree/api/en/zTreeObj.selectNode.html | 66 +- .../zTree/api/en/zTreeObj.setChkDisabled.html | 86 +- .../zTree/api/en/zTreeObj.setEditable.html | 52 +- .../thirdparty/zTree/api/en/zTreeObj.setting.html | 26 +- .../thirdparty/zTree/api/en/zTreeObj.showNode.html | 60 +- .../zTree/api/en/zTreeObj.showNodes.html | 56 +- .../zTree/api/en/zTreeObj.transformToArray.html | 52 +- .../api/en/zTreeObj.transformTozTreeNodes.html | 86 +- .../zTree/api/en/zTreeObj.updateNode.html | 72 +- .../webapp/common/thirdparty/zTree/css/demo.css | 64 +- .../thirdparty/zTree/css/zTreeStyle/zTreeStyle.css | 212 +- .../common/thirdparty/zTree/js/jquery.ztree.all.js | 7012 +- .../thirdparty/zTree/js/jquery.ztree.all.min.js | 320 +- .../thirdparty/zTree/js/jquery.ztree.core.js | 3366 +- .../thirdparty/zTree/js/jquery.ztree.core.min.js | 138 +- .../thirdparty/zTree/js/jquery.ztree.excheck.js | 1256 +- .../zTree/js/jquery.ztree.excheck.min.js | 68 +- .../thirdparty/zTree/js/jquery.ztree.exedit.js | 2380 +- .../thirdparty/zTree/js/jquery.ztree.exedit.min.js | 106 +- .../thirdparty/zTree/js/jquery.ztree.exhide.js | 724 +- .../thirdparty/zTree/js/jquery.ztree.exhide.min.js | 44 +- .../common/thirdparty/zTree/zTree.v3.jquery.json | 70 +- 642 files changed, 186443 insertions(+), 186443 deletions(-) (limited to 'openo-portal/portal-common/src/main/webapp/common/thirdparty') diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/animate/animate.min.css b/openo-portal/portal-common/src/main/webapp/common/thirdparty/animate/animate.min.css index 88b94d50..3a85ab38 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/animate/animate.min.css +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/animate/animate.min.css @@ -1,6 +1,6 @@ -@charset "UTF-8";/*! -Animate.css - http://daneden.me/animate -Licensed under the MIT license - http://opensource.org/licenses/MIT - -Copyright (c) 2014 Daniel Eden +@charset "UTF-8";/*! +Animate.css - http://daneden.me/animate +Licensed under the MIT license - http://opensource.org/licenses/MIT + +Copyright (c) 2014 Daniel Eden */.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}@-webkit-keyframes bounce{0%,100%,20%,53%,80%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1);-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-transition-timing-function:cubic-bezier(0.755,.050,.855,.060);transition-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-transition-timing-function:cubic-bezier(0.755,.050,.855,.060);transition-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{0%,100%,20%,53%,80%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1);-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}40%,43%{-webkit-transition-timing-function:cubic-bezier(0.755,.050,.855,.060);transition-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-30px,0);-ms-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}70%{-webkit-transition-timing-function:cubic-bezier(0.755,.050,.855,.060);transition-timing-function:cubic-bezier(0.755,.050,.855,.060);-webkit-transform:translate3d(0,-15px,0);-ms-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);-ms-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;-ms-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{0%,100%,50%{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,100%,50%{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes pulse{0%{-webkit-transform:scale3d(1,1,1);-ms-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);-ms-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}100%{-webkit-transform:scale3d(1,1,1);-ms-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(0.75,1.25,1);transform:scale3d(0.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes rubberBand{0%{-webkit-transform:scale3d(1,1,1);-ms-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}30%{-webkit-transform:scale3d(1.25,.75,1);-ms-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(0.75,1.25,1);-ms-transform:scale3d(0.75,1.25,1);transform:scale3d(0.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);-ms-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);-ms-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);-ms-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}100%{-webkit-transform:scale3d(1,1,1);-ms-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{0%,100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{0%,100%{-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);-ms-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);-ms-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}100%{-webkit-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}@keyframes swing{20%{-webkit-transform:rotate3d(0,0,1,15deg);-ms-transform:rotate3d(0,0,1,15deg);transform:rotate3d(0,0,1,15deg)}40%{-webkit-transform:rotate3d(0,0,1,-10deg);-ms-transform:rotate3d(0,0,1,-10deg);transform:rotate3d(0,0,1,-10deg)}60%{-webkit-transform:rotate3d(0,0,1,5deg);-ms-transform:rotate3d(0,0,1,5deg);transform:rotate3d(0,0,1,5deg)}80%{-webkit-transform:rotate3d(0,0,1,-5deg);-ms-transform:rotate3d(0,0,1,-5deg);transform:rotate3d(0,0,1,-5deg)}100%{-webkit-transform:rotate3d(0,0,1,0deg);-ms-transform:rotate3d(0,0,1,0deg);transform:rotate3d(0,0,1,0deg)}}.swing{-webkit-transform-origin:top center;-ms-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{0%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}100%{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes tada{0%{-webkit-transform:scale3d(1,1,1);-ms-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);-ms-transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg);transform:scale3d(.9,.9,.9) rotate3d(0,0,1,-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);-ms-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);-ms-transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg);transform:scale3d(1.1,1.1,1.1) rotate3d(0,0,1,-3deg)}100%{-webkit-transform:scale3d(1,1,1);-ms-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}100%{-webkit-transform:none;transform:none}}@keyframes wobble{0%{-webkit-transform:none;-ms-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);-ms-transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg);transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);-ms-transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg);transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);-ms-transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg);transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);-ms-transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg);transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);-ms-transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg);transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}100%{-webkit-transform:none;-ms-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes bounceIn{0%,100%,20%,40%,60%,80%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes bounceIn{0%,100%,20%,40%,60%,80%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);-ms-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);-ms-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);-ms-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);-ms-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);-ms-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}100%{opacity:1;-webkit-transform:scale3d(1,1,1);-ms-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn;-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounceInDown{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInDown{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);-ms-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);-ms-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);-ms-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);-ms-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}100%{-webkit-transform:none;-ms-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);-ms-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);-ms-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);-ms-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);-ms-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}100%{-webkit-transform:none;-ms-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}100%{-webkit-transform:none;transform:none}}@keyframes bounceInRight{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);-ms-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);-ms-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);-ms-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);-ms-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}100%{-webkit-transform:none;-ms-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes bounceInUp{0%,100%,60%,75%,90%{-webkit-transition-timing-function:cubic-bezier(0.215,.61,.355,1);transition-timing-function:cubic-bezier(0.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);-ms-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);-ms-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);-ms-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);-ms-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}100%{-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}100%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);-ms-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);-ms-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}100%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);-ms-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut;-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);-ms-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);-ms-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);-ms-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);-ms-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);-ms-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);-ms-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);-ms-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);-ms-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);-ms-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);-ms-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);-ms-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{opacity:1;-webkit-transform:none;-ms-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);-ms-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}100%{opacity:1;-webkit-transform:none;-ms-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);-ms-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}100%{opacity:1;-webkit-transform:none;-ms-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);-ms-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}100%{opacity:1;-webkit-transform:none;-ms-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);-ms-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}100%{opacity:1;-webkit-transform:none;-ms-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);-ms-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}100%{opacity:1;-webkit-transform:none;-ms-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);-ms-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}100%{opacity:1;-webkit-transform:none;-ms-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);-ms-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}100%{opacity:1;-webkit-transform:none;-ms-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{0%{opacity:1}100%{opacity:0}}@keyframes fadeOut{0%{opacity:1}100%{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,100%,0);-ms-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,2000px,0);-ms-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-100%,0,0);-ms-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);-ms-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0);-ms-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(2000px,0,0);-ms-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-100%,0);-ms-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);-ms-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}100%{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-360deg);-ms-transform:perspective(400px) rotate3d(0,1,0,-360deg);transform:perspective(400px) rotate3d(0,1,0,-360deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-ms-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-190deg);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}50%{-webkit-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-ms-transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);transform:perspective(400px) translate3d(0,0,150px) rotate3d(0,1,0,-170deg);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);-ms-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}100%{-webkit-transform:perspective(400px);-ms-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;-ms-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);-ms-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);-ms-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1,0,0,10deg);-ms-transform:perspective(400px) rotate3d(1,0,0,10deg);transform:perspective(400px) rotate3d(1,0,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-5deg);-ms-transform:perspective(400px) rotate3d(1,0,0,-5deg);transform:perspective(400px) rotate3d(1,0,0,-5deg)}100%{-webkit-transform:perspective(400px);-ms-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;-ms-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}100%{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{0%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);-ms-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-20deg);-ms-transform:perspective(400px) rotate3d(0,1,0,-20deg);transform:perspective(400px) rotate3d(0,1,0,-20deg);-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(0,1,0,10deg);-ms-transform:perspective(400px) rotate3d(0,1,0,10deg);transform:perspective(400px) rotate3d(0,1,0,10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-5deg);-ms-transform:perspective(400px) rotate3d(0,1,0,-5deg);transform:perspective(400px) rotate3d(0,1,0,-5deg)}100%{-webkit-transform:perspective(400px);-ms-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;-ms-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}@keyframes flipOutX{0%{-webkit-transform:perspective(400px);-ms-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(1,0,0,-20deg);-ms-transform:perspective(400px) rotate3d(1,0,0,-20deg);transform:perspective(400px) rotate3d(1,0,0,-20deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(1,0,0,90deg);-ms-transform:perspective(400px) rotate3d(1,0,0,90deg);transform:perspective(400px) rotate3d(1,0,0,90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-animation-duration:.75s;animation-duration:.75s;-webkit-backface-visibility:visible!important;-ms-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}@keyframes flipOutY{0%{-webkit-transform:perspective(400px);-ms-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotate3d(0,1,0,-15deg);-ms-transform:perspective(400px) rotate3d(0,1,0,-15deg);transform:perspective(400px) rotate3d(0,1,0,-15deg);opacity:1}100%{-webkit-transform:perspective(400px) rotate3d(0,1,0,90deg);-ms-transform:perspective(400px) rotate3d(0,1,0,90deg);transform:perspective(400px) rotate3d(0,1,0,90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;-ms-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY;-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}100%{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);-ms-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);-ms-transform:skewX(20deg);transform:skewX(20deg);opacity:1}80%{-webkit-transform:skewX(-5deg);-ms-transform:skewX(-5deg);transform:skewX(-5deg);opacity:1}100%{-webkit-transform:none;-ms-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{0%{opacity:1}100%{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{0%{opacity:1}100%{-webkit-transform:translate3d(100%,0,0) skewX(30deg);-ms-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{0%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{0%{-webkit-transform-origin:center;-ms-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,-200deg);-ms-transform:rotate3d(0,0,1,-200deg);transform:rotate3d(0,0,1,-200deg);opacity:0}100%{-webkit-transform-origin:center;-ms-transform-origin:center;transform-origin:center;-webkit-transform:none;-ms-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{0%{-webkit-transform-origin:left bottom;-ms-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);-ms-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}100%{-webkit-transform-origin:left bottom;-ms-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;-ms-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{0%{-webkit-transform-origin:right bottom;-ms-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,45deg);-ms-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:right bottom;-ms-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;-ms-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{0%{-webkit-transform-origin:left bottom;-ms-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,45deg);-ms-transform:rotate3d(0,0,1,45deg);transform:rotate3d(0,0,1,45deg);opacity:0}100%{-webkit-transform-origin:left bottom;-ms-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:none;-ms-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{0%{-webkit-transform-origin:right bottom;-ms-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-90deg);-ms-transform:rotate3d(0,0,1,-90deg);transform:rotate3d(0,0,1,-90deg);opacity:0}100%{-webkit-transform-origin:right bottom;-ms-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:none;-ms-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{0%{-webkit-transform-origin:center;transform-origin:center;opacity:1}100%{-webkit-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}@keyframes rotateOut{0%{-webkit-transform-origin:center;-ms-transform-origin:center;transform-origin:center;opacity:1}100%{-webkit-transform-origin:center;-ms-transform-origin:center;transform-origin:center;-webkit-transform:rotate3d(0,0,1,200deg);-ms-transform:rotate3d(0,0,1,200deg);transform:rotate3d(0,0,1,200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate(0,0,1,45deg);transform:rotate(0,0,1,45deg);opacity:0}}@keyframes rotateOutDownLeft{0%{-webkit-transform-origin:left bottom;-ms-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;-ms-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate(0,0,1,45deg);-ms-transform:rotate(0,0,1,45deg);transform:rotate(0,0,1,45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutDownRight{0%{-webkit-transform-origin:right bottom;-ms-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;-ms-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,-45deg);-ms-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}@keyframes rotateOutUpLeft{0%{-webkit-transform-origin:left bottom;-ms-transform-origin:left bottom;transform-origin:left bottom;opacity:1}100%{-webkit-transform-origin:left bottom;-ms-transform-origin:left bottom;transform-origin:left bottom;-webkit-transform:rotate3d(0,0,1,-45deg);-ms-transform:rotate3d(0,0,1,-45deg);transform:rotate3d(0,0,1,-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}@keyframes rotateOutUpRight{0%{-webkit-transform-origin:right bottom;-ms-transform-origin:right bottom;transform-origin:right bottom;opacity:1}100%{-webkit-transform-origin:right bottom;-ms-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate3d(0,0,1,90deg);-ms-transform:rotate3d(0,0,1,90deg);transform:rotate3d(0,0,1,90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}100%{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{-webkit-transform-origin:top left;-ms-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate3d(0,0,1,80deg);-ms-transform:rotate3d(0,0,1,80deg);transform:rotate3d(0,0,1,80deg);-webkit-transform-origin:top left;-ms-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}40%,80%{-webkit-transform:rotate3d(0,0,1,60deg);-ms-transform:rotate3d(0,0,1,60deg);transform:rotate3d(0,0,1,60deg);-webkit-transform-origin:top left;-ms-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}100%{-webkit-transform:translate3d(0,700px,0);-ms-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}100%{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);-ms-transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg);transform:translate3d(-100%,0,0) rotate3d(0,0,1,-120deg)}100%{opacity:1;-webkit-transform:none;-ms-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}@keyframes rollOut{0%{opacity:1}100%{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);-ms-transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg);transform:translate3d(100%,0,0) rotate3d(0,0,1,120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);-ms-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-ms-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-ms-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-ms-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-ms-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-ms-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-ms-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-ms-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-ms-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{0%{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:0}}@keyframes zoomOut{0%{opacity:1}50%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);-ms-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}100%{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-ms-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-ms-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;-ms-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);-ms-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);-ms-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;-ms-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);-ms-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}100%{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);-ms-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;-ms-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-ms-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(0.55,.055,.675,.19);animation-timing-function:cubic-bezier(0.55,.055,.675,.19)}100%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-ms-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;-ms-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(0.175,.885,.32,1);animation-timing-function:cubic-bezier(0.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp} \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/avalon/avalon.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/avalon/avalon.js index a22bb7de..786ed3c0 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/avalon/avalon.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/avalon/avalon.js @@ -1,5819 +1,5819 @@ -/*================================================== - Copyright (c) 2013-2015 å¸å¾’正美 and other contributors - http://www.cnblogs.com/rubylouvre/ - https://github.com/RubyLouvre - http://weibo.com/jslouvre/ - - Released under the MIT license - avalon.js 1.45 built in 2015.7.17 - support IE6+ and other browsers - ==================================================*/ -(function(global, factory) { - - if (typeof module === "object" && typeof module.exports === "object") { - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get avalon. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var avalon = require("avalon")(window); - module.exports = global.document ? factory(global, true) : function(w) { - if (!w.document) { - throw new Error("Avalon requires a window with a document") - } - return factory(w) - } - } else { - factory(global) - } - -// Pass this if window is not defined yet -}(typeof window !== "undefined" ? window : this, function(window, noGlobal){ - -/********************************************************************* - * 全局å˜é‡åŠæ–¹æ³• * - **********************************************************************/ -var expose = new Date() - 0 -//http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function -var DOC = window.document -var head = DOC.getElementsByTagName("head")[0] //HEAD元素 -var ifGroup = head.insertBefore(document.createElement("avalon"), head.firstChild) //é¿å…IE6 base标签BUG -ifGroup.innerHTML = "X" -ifGroup.setAttribute("ms-skip", "1") -ifGroup.className = "avalonHide" -var rnative = /\[native code\]/ //判定是å¦åŽŸç”Ÿå‡½æ•° -function log() { - if (window.console && avalon.config.debug) { - // http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log - Function.apply.call(console.log, console, arguments) - } -} - - -var subscribers = "$" + expose -var otherRequire = window.require -var otherDefine = window.define -var innerRequire -var stopRepeatAssign = false -var rword = /[^, ]+/g //切割字符串为一个个å°å—,以空格或豆å·åˆ†å¼€å®ƒä»¬ï¼Œç»“åˆreplace实现字符串的forEach -var rcomplexType = /^(?:object|array)$/ -var rsvg = /^\[object SVG\w*Element\]$/ -var rwindow = /^\[object (?:Window|DOMWindow|global)\]$/ -var oproto = Object.prototype -var ohasOwn = oproto.hasOwnProperty -var serialize = oproto.toString -var ap = Array.prototype -var aslice = ap.slice -var Registry = {} //将函数æ›å…‰åˆ°æ­¤å¯¹è±¡ä¸Šï¼Œæ–¹ä¾¿è®¿é—®å™¨æ”¶é›†ä¾èµ– -var W3C = window.dispatchEvent -var root = DOC.documentElement -var avalonFragment = DOC.createDocumentFragment() -var cinerator = DOC.createElement("div") -var class2type = {} -"Boolean Number String Function Array Date RegExp Object Error".replace(rword, function (name) { - class2type["[object " + name + "]"] = name.toLowerCase() -}) - - -function noop() { -} - - -function oneObject(array, val) { - if (typeof array === "string") { - array = array.match(rword) || [] - } - var result = {}, - value = val !== void 0 ? val : 1 - for (var i = 0, n = array.length; i < n; i++) { - result[array[i]] = value - } - return result -} - -//生æˆUUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript -var generateID = function (prefix) { - prefix = prefix || "avalon" - return String(Math.random() + Math.random()).replace(/\d\.\d{4}/, prefix) -} -function IE() { - if (window.VBArray) { - var mode = document.documentMode - return mode ? mode : window.XMLHttpRequest ? 7 : 6 - } else { - return NaN - } -} -var IEVersion = IE() - -avalon = function (el) { //创建jQueryå¼çš„æ— new 实例化结构 - return new avalon.init(el) -} - -avalon.profile = function () { - if (window.console && avalon.config.profile) { - Function.apply.call(console.log, console, arguments) - } -} - -/*视æµè§ˆå™¨æƒ…况采用最快的异步回调*/ -avalon.nextTick = new function () {// jshint ignore:line - var tickImmediate = window.setImmediate - var tickObserver = window.MutationObserver - var tickPost = W3C && window.postMessage - if (tickImmediate) { - return tickImmediate.bind(window) - } - - var queue = [] - function callback() { - var n = queue.length - for (var i = 0; i < n; i++) { - queue[i]() - } - queue = queue.slice(n) - } - - if (tickObserver) { - var node = document.createTextNode("avalon") - new tickObserver(callback).observe(node, {characterData: true})// jshint ignore:line - return function (fn) { - queue.push(fn) - node.data = Math.random() - } - } - - if (tickPost) { - window.addEventListener("message", function (e) { - var source = e.source - if ((source === window || source === null) && e.data === "process-tick") { - e.stopPropagation() - callback() - } - }) - - return function (fn) { - queue.push(fn) - window.postMessage('process-tick', '*') - } - } - - return function (fn) { - setTimeout(fn, 0) - } -}// jshint ignore:line -/********************************************************************* - * avalonçš„é™æ€æ–¹æ³•å®šä¹‰åŒº * - **********************************************************************/ -avalon.init = function (el) { - this[0] = this.element = el -} -avalon.fn = avalon.prototype = avalon.init.prototype - -avalon.type = function (obj) { //å–得目标的类型 - if (obj == null) { - return String(obj) - } - // 早期的webkit内核æµè§ˆå™¨å®žçŽ°äº†å·²åºŸå¼ƒçš„ecma262v4标准,å¯ä»¥å°†æ­£åˆ™å­—é¢é‡å½“作函数使用,因此typeof在判定正则时会返回function - return typeof obj === "object" || typeof obj === "function" ? - class2type[serialize.call(obj)] || "object" : - typeof obj -} - -var isFunction = typeof alert === "object" ? function (fn) { - try { - return /^\s*\bfunction\b/.test(fn + "") - } catch (e) { - return false - } -} : function (fn) { - return serialize.call(fn) === "[object Function]" -} -avalon.isFunction = isFunction - -avalon.isWindow = function (obj) { - if (!obj) - return false - // 利用IE678 window == document为true,document == window竟然为false的神奇特性 - // 标准æµè§ˆå™¨åŠIE9,IE10等使用 正则检测 - return obj == obj.document && obj.document != obj //jshint ignore:line -} - -function isWindow(obj) { - return rwindow.test(serialize.call(obj)) -} -if (isWindow(window)) { - avalon.isWindow = isWindow -} -var enu -for (enu in avalon({})) { - break -} -var enumerateBUG = enu !== "0" //IE6下为true, 其他为false -/*判定是å¦æ˜¯ä¸€ä¸ªæœ´ç´ çš„javascript对象(Object),ä¸æ˜¯DOM对象,ä¸æ˜¯BOM对象,ä¸æ˜¯è‡ªå®šä¹‰ç±»çš„实例*/ -avalon.isPlainObject = function (obj, key) { - if (!obj || avalon.type(obj) !== "object" || obj.nodeType || avalon.isWindow(obj)) { - return false; - } - try { //IE内置对象没有constructor - if (obj.constructor && !ohasOwn.call(obj, "constructor") && !ohasOwn.call(obj.constructor.prototype, "isPrototypeOf")) { - return false; - } - } catch (e) { //IE8 9会在这里抛错 - return false; - } - if (enumerateBUG) { - for (key in obj) { - return ohasOwn.call(obj, key) - } - } - for (key in obj) { - } - return key === void 0 || ohasOwn.call(obj, key) -} -if (rnative.test(Object.getPrototypeOf)) { - avalon.isPlainObject = function (obj) { - // 简å•çš„ typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通ä¸è¿‡ - return serialize.call(obj) === "[object Object]" && Object.getPrototypeOf(obj) === oproto - } -} -//与jQuery.extend方法,å¯ç”¨äºŽæµ…æ‹·è´ï¼Œæ·±æ‹·è´ -avalon.mix = avalon.fn.mix = function () { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false - - // 如果第一个å‚数为布尔,判定是å¦æ·±æ‹·è´ - if (typeof target === "boolean") { - deep = target - target = arguments[1] || {} - i++ - } - - //ç¡®ä¿æŽ¥å—方为一个å¤æ‚çš„æ•°æ®ç±»åž‹ - if (typeof target !== "object" && !isFunction(target)) { - target = {} - } - - //如果åªæœ‰ä¸€ä¸ªå‚数,那么新æˆå‘˜æ·»åŠ äºŽmix所在的对象上 - if (i === length) { - target = this - i-- - } - - for (; i < length; i++) { - //åªå¤„ç†éžç©ºå‚æ•° - if ((options = arguments[i]) != null) { - for (name in options) { - src = target[name] - try { - copy = options[name] //当options为VBS对象时报错 - } catch (e) { - continue - } - - // 防止环引用 - if (target === copy) { - continue - } - if (deep && copy && (avalon.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { - - if (copyIsArray) { - copyIsArray = false - clone = src && Array.isArray(src) ? src : [] - - } else { - clone = src && avalon.isPlainObject(src) ? src : {} - } - - target[name] = avalon.mix(deep, clone, copy) - } else if (copy !== void 0) { - target[name] = copy - } - } - } - } - return target -} - -function _number(a, len) { //用于模拟slice, splice的效果 - a = Math.floor(a) || 0 - return a < 0 ? Math.max(len + a, 0) : Math.min(a, len); -} -avalon.mix({ - rword: rword, - subscribers: subscribers, - version: 1.45, - ui: {}, - log: log, - slice: W3C ? function (nodes, start, end) { - return aslice.call(nodes, start, end) - } : function (nodes, start, end) { - var ret = [] - var len = nodes.length - if (end === void 0) - end = len - if (typeof end === "number" && isFinite(end)) { - start = _number(start, len) - end = _number(end, len) - for (var i = start; i < end; ++i) { - ret[i - start] = nodes[i] - } - } - return ret - }, - noop: noop, - /*如果ä¸ç”¨Error对象å°è£…一下,str在控制å°ä¸‹å¯èƒ½ä¼šä¹±ç */ - error: function (str, e) { - throw (e || Error)(str) - }, - /*将一个以空格或逗å·éš”开的字符串或数组,转æ¢æˆä¸€ä¸ªé”®å€¼éƒ½ä¸º1的对象*/ - oneObject: oneObject, - /* avalon.range(10) - => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - avalon.range(1, 11) - => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - avalon.range(0, 30, 5) - => [0, 5, 10, 15, 20, 25] - avalon.range(0, -10, -1) - => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] - avalon.range(0) - => []*/ - range: function (start, end, step) { // 用于生æˆæ•´æ•°æ•°ç»„ - step || (step = 1) - if (end == null) { - end = start || 0 - start = 0 - } - var index = -1, - length = Math.max(0, Math.ceil((end - start) / step)), - result = new Array(length) - while (++index < length) { - result[index] = start - start += step - } - return result - }, - eventHooks: [], - /*绑定事件*/ - bind: function(el, type, fn, phase) { - var hooks = avalon.eventHooks - var hook = hooks[type] - if (typeof hook === "object") { - type = hook.type - if (hook.deel) { - fn = hook.deel(el, type, fn, phase) - } - } - var callback = W3C ? fn : function(e) { - fn.call(el, fixEvent(e)); - } - if (W3C) { - el.addEventListener(type, callback, !!phase) - } else { - el.attachEvent("on" + type, callback) - } - return callback - }, - /*å¸è½½äº‹ä»¶*/ - unbind: function(el, type, fn, phase) { - var hooks = avalon.eventHooks - var hook = hooks[type] - var callback = fn || noop - if (typeof hook === "object") { - type = hook.type - if (hook.deel) { - fn = hook.deel(el, type, fn, false) - } - } - if (W3C) { - el.removeEventListener(type, callback, !!phase) - } else { - el.detachEvent("on" + type, callback) - } - }, - /*读写删除元素节点的样å¼*/ - css: function (node, name, value) { - if (node instanceof avalon) { - node = node[0] - } - var prop = /[_-]/.test(name) ? camelize(name) : name, fn - name = avalon.cssName(prop) || prop - if (value === void 0 || typeof value === "boolean") { //获å–æ ·å¼ - fn = cssHooks[prop + ":get"] || cssHooks["@:get"] - if (name === "background") { - name = "backgroundColor" - } - var val = fn(node, name) - return value === true ? parseFloat(val) || 0 : val - } else if (value === "") { //è¯·é™¤æ ·å¼ - node.style[name] = "" - } else { //è®¾ç½®æ ·å¼ - if (value == null || value !== value) { - return - } - if (isFinite(value) && !avalon.cssNumber[prop]) { - value += "px" - } - fn = cssHooks[prop + ":set"] || cssHooks["@:set"] - fn(node, name, value) - } - }, - /*é历数组与对象,回调的第一个å‚数为索引或键å,第二个或元素或键值*/ - each: function (obj, fn) { - if (obj) { //排除null, undefined - var i = 0 - if (isArrayLike(obj)) { - for (var n = obj.length; i < n; i++) { - if (fn(i, obj[i]) === false) - break - } - } else { - for (i in obj) { - if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) { - break - } - } - } - } - }, - //收集元素的data-{{prefix}}-*属性,并转æ¢ä¸ºå¯¹è±¡ - getWidgetData: function (elem, prefix) { - var raw = avalon(elem).data() - var result = {} - for (var i in raw) { - if (i.indexOf(prefix) === 0) { - result[i.replace(prefix, "").replace(/\w/, function (a) { - return a.toLowerCase() - })] = raw[i] - } - } - return result - }, - Array: { - /*åªæœ‰å½“å‰æ•°ç»„ä¸å­˜åœ¨æ­¤å…ƒç´ æ—¶åªæ·»åŠ å®ƒ*/ - ensure: function (target, item) { - if (target.indexOf(item) === -1) { - return target.push(item) - } - }, - /*移除数组中指定ä½ç½®çš„元素,返回布尔表示æˆåŠŸä¸Žå¦*/ - removeAt: function (target, index) { - return !!target.splice(index, 1).length - }, - /*移除数组中第一个匹é…ä¼ å‚的那个元素,返回布尔表示æˆåŠŸä¸Žå¦*/ - remove: function (target, item) { - var index = target.indexOf(item) - if (~index) - return avalon.Array.removeAt(target, index) - return false - } - } -}) - -var bindingHandlers = avalon.bindingHandlers = {} -var bindingExecutors = avalon.bindingExecutors = {} - -/*判定是å¦ç±»æ•°ç»„,如节点集åˆï¼Œçº¯æ•°ç»„,arguments与拥有éžè´Ÿæ•´æ•°çš„length属性的纯JS对象*/ -function isArrayLike(obj) { - if (!obj) - return false - var n = obj.length - if (n === (n >>> 0)) { //检测length属性是å¦ä¸ºéžè´Ÿæ•´æ•° - var type = serialize.call(obj).slice(8, -1) - if (/(?:regexp|string|function|window|global)$/i.test(type)) - return false - if (type === "Array") - return true - try { - if ({}.propertyIsEnumerable.call(obj, "length") === false) { //如果是原生对象 - return /^\s?function/.test(obj.item || obj.callee) - } - return true - } catch (e) { //IEçš„NodeList直接抛错 - return !obj.window //IE6-8 window - } - } - return false -} - - -// https://github.com/rsms/js-lru -var Cache = new function() {// jshint ignore:line - function LRU(maxLength) { - this.size = 0 - this.limit = maxLength - this.head = this.tail = void 0 - this._keymap = {} - } - - var p = LRU.prototype - - p.put = function(key, value) { - var entry = { - key: key, - value: value - } - this._keymap[key] = entry - if (this.tail) { - this.tail.newer = entry - entry.older = this.tail - } else { - this.head = entry - } - this.tail = entry - if (this.size === this.limit) { - this.shift() - } else { - this.size++ - } - return value - } - - p.shift = function() { - var entry = this.head - if (entry) { - this.head = this.head.newer - this.head.older = - entry.newer = - entry.older = - this._keymap[entry.key] = void 0 - } - } - p.get = function(key) { - var entry = this._keymap[key] - if (entry === void 0) - return - if (entry === this.tail) { - return entry.value - } - // HEAD--------------TAIL - // <.older .newer> - // <--- add direction -- - // A B C E - if (entry.newer) { - if (entry === this.head) { - this.head = entry.newer - } - entry.newer.older = entry.older // C <-- E. - } - if (entry.older) { - entry.older.newer = entry.newer // C. --> E - } - entry.newer = void 0 // D --x - entry.older = this.tail // D. --> E - if (this.tail) { - this.tail.newer = entry // E. <-- D - } - this.tail = entry - return entry.value - } - return LRU -}// jshint ignore:line - -/********************************************************************* - * javascript åº•å±‚è¡¥ä¸ * - **********************************************************************/ -if (!"å¸å¾’正美".trim) { - var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g - String.prototype.trim = function () { - return this.replace(rtrim, "") - } -} -var hasDontEnumBug = !({ - 'toString': null -}).propertyIsEnumerable('toString'), - hasProtoEnumBug = (function () { - }).propertyIsEnumerable('prototype'), - dontEnums = [ - "toString", - "toLocaleString", - "valueOf", - "hasOwnProperty", - "isPrototypeOf", - "propertyIsEnumerable", - "constructor" - ], - dontEnumsLength = dontEnums.length; -if (!Object.keys) { - Object.keys = function (object) { //ecma262v5 15.2.3.14 - var theKeys = [] - var skipProto = hasProtoEnumBug && typeof object === "function" - if (typeof object === "string" || (object && object.callee)) { - for (var i = 0; i < object.length; ++i) { - theKeys.push(String(i)) - } - } else { - for (var name in object) { - if (!(skipProto && name === "prototype") && ohasOwn.call(object, name)) { - theKeys.push(String(name)) - } - } - } - - if (hasDontEnumBug) { - var ctor = object.constructor, - skipConstructor = ctor && ctor.prototype === object - for (var j = 0; j < dontEnumsLength; j++) { - var dontEnum = dontEnums[j] - if (!(skipConstructor && dontEnum === "constructor") && ohasOwn.call(object, dontEnum)) { - theKeys.push(dontEnum) - } - } - } - return theKeys - } -} -if (!Array.isArray) { - Array.isArray = function (a) { - return serialize.call(a) === "[object Array]" - } -} - -if (!noop.bind) { - Function.prototype.bind = function (scope) { - if (arguments.length < 2 && scope === void 0) - return this - var fn = this, - argv = arguments - return function () { - var args = [], - i - for (i = 1; i < argv.length; i++) - args.push(argv[i]) - for (i = 0; i < arguments.length; i++) - args.push(arguments[i]) - return fn.apply(scope, args) - } - } -} - -function iterator(vars, body, ret) { - var fun = 'for(var ' + vars + 'i=0,n = this.length; i < n; i++){' + body.replace('_', '((i in this) && fn.call(scope,this[i],i,this))') + '}' + ret - /* jshint ignore:start */ - return Function("fn,scope", fun) - /* jshint ignore:end */ -} -if (!rnative.test([].map)) { - avalon.mix(ap, { - //定ä½æ“作,返回数组中第一个等于给定å‚数的元素的索引值。 - indexOf: function (item, index) { - var n = this.length, - i = ~~index - if (i < 0) - i += n - for (; i < n; i++) - if (this[i] === item) - return i - return -1 - }, - //定ä½æ“作,åŒä¸Šï¼Œä¸è¿‡æ˜¯ä»ŽåŽé历。 - lastIndexOf: function (item, index) { - var n = this.length, - i = index == null ? n - 1 : index - if (i < 0) - i = Math.max(0, n + i) - for (; i >= 0; i--) - if (this[i] === item) - return i - return -1 - }, - //迭代æ“作,将数组的元素挨个儿传入一个函数中执行。Prototype.js的对应å字为each。 - forEach: iterator("", '_', ""), - //迭代类 在数组中的æ¯ä¸ªé¡¹ä¸Šè¿è¡Œä¸€ä¸ªå‡½æ•°ï¼Œå¦‚果此函数的值为真,则此元素作为新数组的元素收集起æ¥ï¼Œå¹¶è¿”回新数组 - filter: iterator('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r'), - //收集æ“作,将数组的元素挨个儿传入一个函数中执行,然åŽæŠŠå®ƒä»¬çš„返回值组æˆä¸€ä¸ªæ–°æ•°ç»„返回。Prototype.js的对应å字为collect。 - map: iterator('r=[],', 'r[i]=_', 'return r'), - //åªè¦æ•°ç»„中有一个元素满足æ¡ä»¶ï¼ˆæ”¾è¿›ç»™å®šå‡½æ•°è¿”回true),那么它就返回true。Prototype.js的对应å字为any。 - some: iterator("", 'if(_)return true', 'return false'), - //åªæœ‰æ•°ç»„中的元素都满足æ¡ä»¶ï¼ˆæ”¾è¿›ç»™å®šå‡½æ•°è¿”回true),它æ‰è¿”回true。Prototype.js的对应å字为all。 - every: iterator("", 'if(!_)return false', 'return true') - }) -} -/********************************************************************* - * DOM åº•å±‚è¡¥ä¸ * - **********************************************************************/ - -function fixContains(root, el) { - try { //IE6-8,游离于DOM树外的文本节点,访问parentNode有时会抛错 - while ((el = el.parentNode)) - if (el === root) - return true - return false - } catch (e) { - return false - } -} -avalon.contains = fixContains -//IE6-11的文档对象没有contains -if (!DOC.contains) { - DOC.contains = function (b) { - return fixContains(DOC, b) - } -} - -function outerHTML() { - return new XMLSerializer().serializeToString(this) -} - -if (window.SVGElement) { - //safari5+是把contains方法放在Element.prototype上而ä¸æ˜¯Node.prototype - if (!DOC.createTextNode("x").contains) { - Node.prototype.contains = function (arg) {//IE6-8没有Node对象 - return !!(this.compareDocumentPosition(arg) & 16) - } - } - var svgns = "http://www.w3.org/2000/svg" - var svg = DOC.createElementNS(svgns, "svg") - svg.innerHTML = '' - if (!rsvg.test(svg.firstChild)) { // #409 - function enumerateNode(node, targetNode) {// jshint ignore:line - if (node && node.childNodes) { - var nodes = node.childNodes - for (var i = 0, el; el = nodes[i++]; ) { - if (el.tagName) { - var svg = DOC.createElementNS(svgns, - el.tagName.toLowerCase()) - ap.forEach.call(el.attributes, function (attr) { - svg.setAttribute(attr.name, attr.value) //å¤åˆ¶å±žæ€§ - })// jshint ignore:line - // 递归处ç†å­èŠ‚点 - enumerateNode(el, svg) - targetNode.appendChild(svg) - } - } - } - } - Object.defineProperties(SVGElement.prototype, { - "outerHTML": {//IE9-11,firefoxä¸æ”¯æŒSVG元素的innerHTML,outerHTML属性 - enumerable: true, - configurable: true, - get: outerHTML, - set: function (html) { - var tagName = this.tagName.toLowerCase(), - par = this.parentNode, - frag = avalon.parseHTML(html) - // æ“作的svg,直接æ’å…¥ - if (tagName === "svg") { - par.insertBefore(frag, this) - // svg节点的å­èŠ‚点类似 - } else { - var newFrag = DOC.createDocumentFragment() - enumerateNode(frag, newFrag) - par.insertBefore(newFrag, this) - } - par.removeChild(this) - } - }, - "innerHTML": { - enumerable: true, - configurable: true, - get: function () { - var s = this.outerHTML - var ropen = new RegExp("<" + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', "i") - var rclose = new RegExp("<\/" + this.nodeName + ">$", "i") - return s.replace(ropen, "").replace(rclose, "") - }, - set: function (html) { - if (avalon.clearHTML) { - avalon.clearHTML(this) - var frag = avalon.parseHTML(html) - enumerateNode(frag, this) - } - } - } - }) - } -} -if (!root.outerHTML && window.HTMLElement) { //firefox 到11æ—¶æ‰æœ‰outerHTML - HTMLElement.prototype.__defineGetter__("outerHTML", outerHTML); -} - - -//============================= event binding ======================= -var rmouseEvent = /^(?:mouse|contextmenu|drag)|click/ -function fixEvent(event) { - var ret = {} - for (var i in event) { - ret[i] = event[i] - } - var target = ret.target = event.srcElement - if (event.type.indexOf("key") === 0) { - ret.which = event.charCode != null ? event.charCode : event.keyCode - } else if (rmouseEvent.test(event.type)) { - var doc = target.ownerDocument || DOC - var box = doc.compatMode === "BackCompat" ? doc.body : doc.documentElement - ret.pageX = event.clientX + (box.scrollLeft >> 0) - (box.clientLeft >> 0) - ret.pageY = event.clientY + (box.scrollTop >> 0) - (box.clientTop >> 0) - ret.wheelDeltaY = ret.wheelDelta - ret.wheelDeltaX = 0 - } - ret.timeStamp = new Date() - 0 - ret.originalEvent = event - ret.preventDefault = function () { //阻止默认行为 - event.returnValue = false - } - ret.stopPropagation = function () { //阻止事件在DOM树中的传播 - event.cancelBubble = true - } - return ret -} - -var eventHooks = avalon.eventHooks -//针对firefox, chrome修正mouseenter, mouseleave -if (!("onmouseenter" in root)) { - avalon.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" - }, function (origType, fixType) { - eventHooks[origType] = { - type: fixType, - deel: function (elem, _, fn) { - return function (e) { - var t = e.relatedTarget - if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) { - delete e.type - e.type = origType - return fn.call(elem, e) - } - } - } - } - }) -} -//针对IE9+, w3c修正animationend -avalon.each({ - AnimationEvent: "animationend", - WebKitAnimationEvent: "webkitAnimationEnd" -}, function (construct, fixType) { - if (window[construct] && !eventHooks.animationend) { - eventHooks.animationend = { - type: fixType - } - } -}) -//针对IE6-8修正input -if (!("oninput" in DOC.createElement("input"))) { - eventHooks.input = { - type: "propertychange", - deel: function (elem, _, fn) { - return function (e) { - if (e.propertyName === "value") { - e.type = "input" - return fn.call(elem, e) - } - } - } - } -} -if (DOC.onmousewheel === void 0) { - /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120 - firefox DOMMouseScroll detail 下3 上-3 - firefox wheel detlaY 下3 上-3 - IE9-11 wheel deltaY 下40 上-40 - chrome wheel deltaY 下100 上-100 */ - var fixWheelType = DOC.onwheel !== void 0 ? "wheel" : "DOMMouseScroll" - var fixWheelDelta = fixWheelType === "wheel" ? "deltaY" : "detail" - eventHooks.mousewheel = { - type: fixWheelType, - deel: function (elem, _, fn) { - return function (e) { - e.wheelDeltaY = e.wheelDelta = e[fixWheelDelta] > 0 ? -120 : 120 - e.wheelDeltaX = 0 - if (Object.defineProperty) { - Object.defineProperty(e, "type", { - value: "mousewheel" - }) - } - fn.call(elem, e) - } - } - } -} - - - -/********************************************************************* - * é…置系统 * - **********************************************************************/ - -function kernel(settings) { - for (var p in settings) { - if (!ohasOwn.call(settings, p)) - continue - var val = settings[p] - if (typeof kernel.plugins[p] === "function") { - kernel.plugins[p](val) - } else if (typeof kernel[p] === "object") { - avalon.mix(kernel[p], val) - } else { - kernel[p] = val - } - } - return this -} -var openTag, closeTag, rexpr, rexprg, rbind, rregexp = /[-.*+?^${}()|[\]\/\\]/g - -function escapeRegExp(target) { - //http://stevenlevithan.com/regex/xregexp/ - //将字符串安全格å¼åŒ–为正则表达å¼çš„æºç  - return (target + "").replace(rregexp, "\\$&") -} - -var plugins = { - loader: function (builtin) { - var flag = innerRequire && builtin - window.require = flag ? innerRequire : otherRequire - window.define = flag ? innerRequire.define : otherDefine - }, - interpolate: function (array) { - openTag = array[0] - closeTag = array[1] - if (openTag === closeTag) { - throw new SyntaxError("openTag!==closeTag") - var test = openTag + "test" + closeTag - cinerator.innerHTML = test - if (cinerator.innerHTML !== test && cinerator.innerHTML.indexOf("<") > -1) { - throw new SyntaxError("此定界符ä¸åˆæ³•") - } - cinerator.innerHTML = "" - } - var o = escapeRegExp(openTag), - c = escapeRegExp(closeTag) - rexpr = new RegExp(o + "(.*?)" + c) - rexprg = new RegExp(o + "(.*?)" + c, "g") - rbind = new RegExp(o + ".*?" + c + "|\\sms-") - } -} - -kernel.debug = true -kernel.plugins = plugins -kernel.plugins['interpolate'](["{{", "}}"]) -kernel.paths = {} -kernel.shim = {} -kernel.maxRepeatSize = 100 -avalon.config = kernel -var ravalon = /(\w+)\[(avalonctrl)="(\S+)"\]/ -var findNodes = DOC.querySelectorAll ? function(str) { - return DOC.querySelectorAll(str) -} : function(str) { - var match = str.match(ravalon) - var all = DOC.getElementsByTagName(match[1]) - var nodes = [] - for (var i = 0, el; el = all[i++]; ) { - if (el.getAttribute(match[2]) === match[3]) { - nodes.push(el) - } - } - return nodes -} -/********************************************************************* - * 事件总线 * - **********************************************************************/ -var EventBus = { - $watch: function (type, callback) { - if (typeof callback === "function") { - var callbacks = this.$events[type] - if (callbacks) { - callbacks.push(callback) - } else { - this.$events[type] = [callback] - } - } else { //é‡æ–°å¼€å§‹ç›‘å¬æ­¤VM的第一é‡ç®€å•å±žæ€§çš„å˜åŠ¨ - this.$events = this.$watch.backup - } - return this - }, - $unwatch: function (type, callback) { - var n = arguments.length - if (n === 0) { //让此VM的所有$watch回调无效化 - this.$watch.backup = this.$events - this.$events = {} - } else if (n === 1) { - this.$events[type] = [] - } else { - var callbacks = this.$events[type] || [] - var i = callbacks.length - while (~--i < 0) { - if (callbacks[i] === callback) { - return callbacks.splice(i, 1) - } - } - } - return this - }, - $fire: function (type) { - var special, i, v, callback - if (/^(\w+)!(\S+)$/.test(type)) { - special = RegExp.$1 - type = RegExp.$2 - } - var events = this.$events - if (!events) - return - var args = aslice.call(arguments, 1) - var detail = [type].concat(args) - if (special === "all") { - for (i in avalon.vmodels) { - v = avalon.vmodels[i] - if (v !== this) { - v.$fire.apply(v, detail) - } - } - } else if (special === "up" || special === "down") { - var elements = events.expr ? findNodes(events.expr) : [] - if (elements.length === 0) - return - for (i in avalon.vmodels) { - v = avalon.vmodels[i] - if (v !== this) { - if (v.$events.expr) { - var eventNodes = findNodes(v.$events.expr) - if (eventNodes.length === 0) { - continue - } - //循环两个vmodel中的节点,查找匹é…(å‘上匹é…或者å‘下匹é…)的节点并设置标识 - /* jshint ignore:start */ - ap.forEach.call(eventNodes, function (node) { - ap.forEach.call(elements, function (element) { - var ok = special === "down" ? element.contains(node) : //å‘下æ•èŽ· - node.contains(element) //å‘上冒泡 - if (ok) { - node._avalon = v //符åˆæ¡ä»¶çš„加一个标识 - } - }); - }) - /* jshint ignore:end */ - } - } - } - var nodes = DOC.getElementsByTagName("*") //å®žçŽ°èŠ‚ç‚¹æŽ’åº - var alls = [] - ap.forEach.call(nodes, function (el) { - if (el._avalon) { - alls.push(el._avalon) - el._avalon = "" - el.removeAttribute("_avalon") - } - }) - if (special === "up") { - alls.reverse() - } - for (i = 0; callback = alls[i++]; ) { - if (callback.$fire.apply(callback, detail) === false) { - break - } - } - } else { - var callbacks = events[type] || [] - var all = events.$all || [] - for (i = 0; callback = callbacks[i++]; ) { - if (isFunction(callback)) - callback.apply(this, args) - } - for (i = 0; callback = all[i++]; ) { - if (isFunction(callback)) - callback.apply(this, arguments) - } - } - } -} - -/********************************************************************* - * modelFactory * - **********************************************************************/ -//avalon最核心的方法的两个方法之一(å¦ä¸€ä¸ªæ˜¯avalon.scan),返回一个ViewModel(VM) -var VMODELS = avalon.vmodels = {} //所有vmodel都储存在这里 -avalon.define = function (id, factory) { - var $id = id.$id || id - if (!$id) { - log("warning: vm必须指定$id") - } - if (VMODELS[$id]) { - log("warning: " + $id + " å·²ç»å­˜åœ¨äºŽavalon.vmodels中") - } - if (typeof id === "object") { - var model = modelFactory(id) - } else { - var scope = { - $watch: noop - } - factory(scope) //得到所有定义 - - model = modelFactory(scope) //å·å¤©æ¢æ—¥ï¼Œå°†scopeæ¢ä¸ºmodel - stopRepeatAssign = true - factory(model) - stopRepeatAssign = false - } - model.$id = $id - return VMODELS[$id] = model -} - -//一些ä¸éœ€è¦è¢«ç›‘å¬çš„属性 -var $$skipArray = String("$id,$watch,$unwatch,$fire,$events,$model,$skipArray,$proxy,$reinitialize,$propertyNames").match(rword) -var defineProperty = Object.defineProperty -var canHideOwn = true -//如果æµè§ˆå™¨ä¸æ”¯æŒecma262v5çš„Object.defineProperties或者存在BUG,比如IE8 -//标准æµè§ˆå™¨ä½¿ç”¨__defineGetter__, __defineSetter__实现 -try { - defineProperty({}, "_", { - value: "x" - }) - var defineProperties = Object.defineProperties -} catch (e) { - canHideOwn = false -} - -function modelFactory(source, $special, $model) { - if (Array.isArray(source)) { - var arr = source.concat() - source.length = 0 - var collection = arrayFactory(source) - collection.pushArray(arr) - return collection - } - //0 null undefined || Node || VModel(fix IE6-8 createWithProxy $val: val引å‘çš„BUG) - if (!source || source.nodeType > 0 || (source.$id && source.$events)) { - return source - } - var $skipArray = Array.isArray(source.$skipArray) ? source.$skipArray : [] - $skipArray.$special = $special || {} //强制è¦ç›‘å¬çš„属性 - var $vmodel = {} //è¦è¿”回的对象, 它在IE6-8下å¯èƒ½è¢«å·é¾™è½¬å‡¤ - $model = $model || {} //vmodels.$model属性 - var $events = {} //vmodel.$events属性 - var accessors = {} //监控属性 - var computed = [] - $$skipArray.forEach(function (name) { - delete source[name] - }) - var names = Object.keys(source) - /* jshint ignore:start */ - names.forEach(function (name, accessor) { - var val = source[name] - $model[name] = val - if (isObservable(name, val, $skipArray)) { - //总共产生三ç§accessor - $events[name] = [] - var valueType = avalon.type(val) - //总共产生三ç§accessor - if (valueType === "object" && isFunction(val.get) && Object.keys(val).length <= 2) { - accessor = makeComputedAccessor(name, val) - computed.push(accessor) - } else if (rcomplexType.test(valueType)) { - accessor = makeComplexAccessor(name, val, valueType, $events[name]) - } else { - accessor = makeSimpleAccessor(name, val) - } - accessors[name] = accessor - } - }) - /* jshint ignore:end */ - - $vmodel = defineProperties($vmodel, descriptorFactory(accessors), source) //生æˆä¸€ä¸ªç©ºçš„ViewModel - for (var i = 0; i < names.length; i++) { - var name = names[i] - if (!accessors[name]) { - $vmodel[name] = source[name] - } - } - //添加$id, $model, $events, $watch, $unwatch, $fire - $vmodel.$propertyNames = names.join("­") - $vmodel.$id = generateID() - $vmodel.$model = $model - $vmodel.$events = $events - for (i in EventBus) { - var fn = EventBus[i] - if (!W3C) { //在IE6-8下,VB对象的方法里的this并ä¸æŒ‡å‘自身,需è¦ç”¨bind处ç†ä¸€ä¸‹ - fn = fn.bind($vmodel) - } - $vmodel[i] = fn - } - if (canHideOwn) { - Object.defineProperty($vmodel, "hasOwnProperty", hasOwnDescriptor) - } else { - /* jshint ignore:start */ - $vmodel.hasOwnProperty = function (name) { - return name in $vmodel.$model - } - /* jshint ignore:end */ - } - - $vmodel.$reinitialize = function () { - computed.forEach(function (accessor) { - delete accessor._value - delete accessor.oldArgs - accessor.digest = function () { - accessor.call($vmodel) - } - dependencyDetection.begin({ - callback: function (vm, dependency) {//dependency为一个accessor - var name = dependency._name - if (dependency !== accessor) { - var list = vm.$events[name] - injectDependency(list, accessor.digest) - } - } - }) - try { - accessor.get.call($vmodel) - } finally { - dependencyDetection.end() - } - }) - } - $vmodel.$reinitialize() - return $vmodel -} - -var hasOwnDescriptor = { - value: function (name) { - return name in this.$model - }, - writable: false, - enumerable: false, - configurable: true -} -//创建一个简å•è®¿é—®å™¨ -function makeSimpleAccessor(name, value) { - function accessor(value) { - var oldValue = accessor._value - if (arguments.length > 0) { - if (!stopRepeatAssign && !isEqual(value, oldValue)) { - accessor.updateValue(this, value) - accessor.notify(this, value, oldValue) - } - return this - } else { - dependencyDetection.collectDependency(this, accessor) - return oldValue - } - } - accessorFactory(accessor, name) - accessor._value = value - return accessor; -} - -//创建一个计算访问器 -function makeComputedAccessor(name, options) { - function accessor(value) {//计算属性 - var oldValue = accessor._value - var init = ("_value" in accessor) - if (arguments.length > 0) { - if (stopRepeatAssign) { - return this - } - if (typeof accessor.set === "function") { - if (accessor.oldArgs !== value) { - accessor.oldArgs = value - var $events = this.$events - var lock = $events[name] - $events[name] = [] //清空回调,防止内部冒泡而触å‘多次$fire - accessor.set.call(this, value) - $events[name] = lock - value = accessor.get.call(this) - if (value !== oldValue) { - accessor.updateValue(this, value) - accessor.notify(this, value, oldValue) //触å‘$watch回调 - } - } - } - return this - } else { - //å°†ä¾èµ–于自己的高层访问器或视图刷新函数(以绑定对象形å¼ï¼‰æ”¾åˆ°è‡ªå·±çš„订阅数组中 - //将自己注入到低层访问器的订阅数组中 - value = accessor.get.call(this) - accessor.updateValue(this, value) - if (init && oldValue !== value) { - accessor.notify(this, value, oldValue) //触å‘$watch回调 - } - return value - } - } - accessor.set = options.set - accessor.get = options.get - accessorFactory(accessor, name) - return accessor -} - -//创建一个å¤æ‚访问器 -function makeComplexAccessor(name, initValue, valueType, list) { - function accessor(value) { - var oldValue = accessor._value - - var son = accessor._vmodel - if (arguments.length > 0) { - if (stopRepeatAssign) { - return this - } - if (valueType === "array") { - var a = son, b = value, - an = a.length, - bn = b.length - a.$lock = true - if (an > bn) { - a.splice(bn, an - bn) - } else if (bn > an) { - a.push.apply(a, b.slice(an)) - } - var n = Math.min(an, bn) - for (var i = 0; i < n; i++) { - a.set(i, b[i]) - } - delete a.$lock - a._fire("set") - } else if (valueType === "object") { - var newPropertyNames = Object.keys(value).join("­") - if (son.$propertyNames === newPropertyNames) { - for (i in value) { - son[i] = value[i] - } - } else { - var sson = accessor._vmodel = modelFactory(value) - var sevent = sson.$events - var oevent = son.$events - for (var i in sevent) { - var arr = sevent[i] - if (Array.isArray(arr)) { - arr = arr.concat(oevent[i]) - } - } - sevent[subscribers] = oevent[subscribers] - sson.$proxy = son.$proxy - son = sson - } - } - accessor.updateValue(this, son.$model) - accessor.notify(this, this._value, oldValue) - return this - } else { - dependencyDetection.collectDependency(this, accessor) - return son - } - } - accessorFactory(accessor, name) - var son = accessor._vmodel = modelFactory(initValue) - son.$events[subscribers] = list - return accessor -} - -function globalUpdateValue(vmodel, value) { - vmodel.$model[this._name] = this._value = value -} - -function globalNotify(vmodel, value, oldValue) { - var name = this._name - var array = vmodel.$events[name] //刷新值 - if (array) { - fireDependencies(array) //åŒæ­¥è§†å›¾ - EventBus.$fire.call(vmodel, name, value, oldValue) //触å‘$watch回调 - } -} - -function accessorFactory(accessor, name) { - accessor._name = name - //åŒæ—¶æ›´æ–°_value与model - accessor.updateValue = globalUpdateValue - accessor.notify = globalNotify -} - -//比较两个值是å¦ç›¸ç­‰ -var isEqual = Object.is || function (v1, v2) { - if (v1 === 0 && v2 === 0) { - return 1 / v1 === 1 / v2 - } else if (v1 !== v1) { - return v2 !== v2 - } else { - return v1 === v2 - } -} - -function isObservable(name, value, $skipArray) { - if (isFunction(value) || value && value.nodeType) { - return false - } - if ($skipArray.indexOf(name) !== -1) { - return false - } - var $special = $skipArray.$special - if (name && name.charAt(0) === "$" && !$special[name]) { - return false - } - return true -} - -var descriptorFactory = W3C ? function (obj) { - var descriptors = {} - for (var i in obj) { - descriptors[i] = { - get: obj[i], - set: obj[i], - enumerable: true, - configurable: true - } - } - return descriptors -} : function (a) { - return a -} - -//===================ä¿®å¤æµè§ˆå™¨å¯¹Object.defineProperties的支æŒ================= -if (!canHideOwn) { - if ("__defineGetter__" in avalon) { - defineProperty = function (obj, prop, desc) { - if ('value' in desc) { - obj[prop] = desc.value - } - if ("get" in desc) { - obj.__defineGetter__(prop, desc.get) - } - if ('set' in desc) { - obj.__defineSetter__(prop, desc.set) - } - return obj - } - defineProperties = function (obj, descs) { - for (var prop in descs) { - if (descs.hasOwnProperty(prop)) { - defineProperty(obj, prop, descs[prop]) - } - } - return obj - } - } - if (IEVersion) { - var VBClassPool = {} - window.execScript([// jshint ignore:line - "Function parseVB(code)", - "\tExecuteGlobal(code)", - "End Function" //转æ¢ä¸€æ®µæ–‡æœ¬ä¸ºVBä»£ç  - ].join("\n"), "VBScript") - function VBMediator(instance, accessors, name, value) {// jshint ignore:line - var accessor = accessors[name] - if (arguments.length === 4) { - accessor.call(instance, value) - } else { - return accessor.call(instance) - } - } - defineProperties = function (name, accessors, properties) { - // jshint ignore:line - var buffer = [] - buffer.push( - "\r\n\tPrivate [__data__], [__proxy__]", - "\tPublic Default Function [__const__](d, p)", - "\t\tSet [__data__] = d: set [__proxy__] = p", - "\t\tSet [__const__] = Me", //链å¼è°ƒç”¨ - "\tEnd Function") - //添加普通属性,因为VBScript对象ä¸èƒ½åƒJS那样éšæ„增删属性,必须在这里预先定义好 - for (name in properties) { - if (!accessors.hasOwnProperty(name)) { - buffer.push("\tPublic [" + name + "]") - } - } - $$skipArray.forEach(function (name) { - if (!accessors.hasOwnProperty(name)) { - buffer.push("\tPublic [" + name + "]") - } - }) - buffer.push("\tPublic [" + 'hasOwnProperty' + "]") - //添加访问器属性 - for (name in accessors) { - buffer.push( - //由于ä¸çŸ¥å¯¹æ–¹ä¼šä¼ å…¥ä»€ä¹ˆ,å› æ­¤set, let都用上 - "\tPublic Property Let [" + name + "](val" + expose + ")", //setter - "\t\tCall [__proxy__](Me,[__data__], \"" + name + "\", val" + expose + ")", - "\tEnd Property", - "\tPublic Property Set [" + name + "](val" + expose + ")", //setter - "\t\tCall [__proxy__](Me,[__data__], \"" + name + "\", val" + expose + ")", - "\tEnd Property", - "\tPublic Property Get [" + name + "]", //getter - "\tOn Error Resume Next", //必须优先使用set语å¥,å¦åˆ™å®ƒä¼šè¯¯å°†æ•°ç»„当字符串返回 - "\t\tSet[" + name + "] = [__proxy__](Me,[__data__],\"" + name + "\")", - "\tIf Err.Number <> 0 Then", - "\t\t[" + name + "] = [__proxy__](Me,[__data__],\"" + name + "\")", - "\tEnd If", - "\tOn Error Goto 0", - "\tEnd Property") - - } - - buffer.push("End Class") - var body = buffer.join("\r\n") - var className =VBClassPool[body] - if (!className) { - className = generateID("VBClass") - window.parseVB("Class " + className + body) - window.parseVB([ - "Function " + className + "Factory(a, b)", //创建实例并传入两个关键的å‚æ•° - "\tDim o", - "\tSet o = (New " + className + ")(a, b)", - "\tSet " + className + "Factory = o", - "End Function" - ].join("\r\n")) - VBClassPool[body] = className - } - var ret = window[className + "Factory"](accessors, VBMediator) //å¾—åˆ°å…¶äº§å“ - return ret //å¾—åˆ°å…¶äº§å“ - } - } -} - -/********************************************************************* - * 监控数组(与ms-each, ms-repeaté…åˆä½¿ç”¨ï¼‰ * - **********************************************************************/ - -function arrayFactory(model) { - var array = [] - array.$id = generateID() - array.$model = model //æ•°æ®æ¨¡åž‹ - array.$events = {} - array.$events[subscribers] = [] - array._ = modelFactory({ - length: model.length - }) - array._.$watch("length", function (a, b) { - array.$fire("length", a, b) - }) - for (var i in EventBus) { - array[i] = EventBus[i] - } - avalon.mix(array, arrayPrototype) - return array -} - -function mutateArray(method, pos, n, index, method2, pos2, n2) { - var oldLen = this.length, loop = 2 - while (--loop) { - switch (method) { - case "add": - /* jshint ignore:start */ - var array = this.$model.slice(pos, pos + n).map(function (el) { - if (rcomplexType.test(avalon.type(el))) { - return el.$id ? el : modelFactory(el, 0, el) - } else { - return el - } - }) - /* jshint ignore:end */ - _splice.apply(this, [pos, 0].concat(array)) - this._fire("add", pos, n) - break - case "del": - var ret = this._splice(pos, n) - this._fire("del", pos, n) - break - } - if (method2) { - method = method2 - pos = pos2 - n = n2 - loop = 2 - method2 = 0 - } - } - this._fire("index", index) - if (this.length !== oldLen) { - this._.length = this.length - } - return ret -} - -var _splice = ap.splice -var arrayPrototype = { - _splice: _splice, - _fire: function (method, a, b) { - fireDependencies(this.$events[subscribers], method, a, b) - }, - size: function () { //å–得数组长度,这个函数å¯ä»¥åŒæ­¥è§†å›¾ï¼Œlengthä¸èƒ½ - return this._.length - }, - pushArray: function (array) { - var m = array.length, n = this.length - if (m) { - ap.push.apply(this.$model, array) - mutateArray.call(this, "add", n, m, Math.max(0, n - 1)) - } - return m + n - }, - push: function () { - //http://jsperf.com/closure-with-arguments - var array = [] - var i, n = arguments.length - for (i = 0; i < n; i++) { - array[i] = arguments[i] - } - return this.pushArray(array) - }, - unshift: function () { - var m = arguments.length, n = this.length - if (m) { - ap.unshift.apply(this.$model, arguments) - mutateArray.call(this, "add", 0, m, 0) - } - return m + n //IE67çš„unshiftä¸ä¼šè¿”回长度 - }, - shift: function () { - if (this.length) { - var el = this.$model.shift() - mutateArray.call(this, "del", 0, 1, 0) - return el //返回被移除的元素 - } - }, - pop: function () { - var n = this.length - if (n) { - var el = this.$model.pop() - mutateArray.call(this, "del", n - 1, 1, Math.max(0, n - 2)) - return el //返回被移除的元素 - } - }, - splice: function (start) { - var m = arguments.length, args = [], change - var removed = _splice.apply(this.$model, arguments) - if (removed.length) { //如果用户删掉了元素 - args.push("del", start, removed.length, 0) - change = true - } - if (m > 2) { //如果用户添加了元素 - if (change) { - args.splice(3, 1, 0, "add", start, m - 2) - } else { - args.push("add", start, m - 2, 0) - } - change = true - } - if (change) { //返回被移除的元素 - return mutateArray.apply(this, args) - } else { - return [] - } - }, - contains: function (el) { //判定是å¦åŒ…å« - return this.indexOf(el) !== -1 - }, - remove: function (el) { //移除第一个等于给定值的元素 - return this.removeAt(this.indexOf(el)) - }, - removeAt: function (index) { //移除指定索引上的元素 - if (index >= 0) { - this.$model.splice(index, 1) - return mutateArray.call(this, "del", index, 1, 0) - } - return [] - }, - clear: function () { - this.$model.length = this.length = this._.length = 0 //清空数组 - this._fire("clear", 0) - return this - }, - removeAll: function (all) { //移除N个元素 - if (Array.isArray(all)) { - for (var i = this.length - 1; i >= 0; i--) { - if (all.indexOf(this[i]) !== -1) { - this.removeAt(i) - } - } - } else if (typeof all === "function") { - for ( i = this.length - 1; i >= 0; i--) { - var el = this[i] - if (all(el, i)) { - this.removeAt(i) - } - } - } else { - this.clear() - } - }, - ensure: function (el) { - if (!this.contains(el)) { //åªæœ‰ä¸å­˜åœ¨æ‰push - this.push(el) - } - return this - }, - set: function (index, val) { - if (index >= 0) { - var valueType = avalon.type(val) - if (val && val.$model) { - val = val.$model - } - var target = this[index] - if (valueType === "object") { - for (var i in val) { - if (target.hasOwnProperty(i)) { - target[i] = val[i] - } - } - } else if (valueType === "array") { - target.clear().push.apply(target, val) - } else if (target !== val) { - this[index] = val - this.$model[index] = val - this._fire("set", index, val) - } - } - return this - } -} -//相当于原æ¥bindingExecutors.repeat çš„index分支 -function resetIndex(array, pos) { - var last = array.length - 1 - for (var el; el = array[pos]; pos++) { - el.$index = pos - el.$first = pos === 0 - el.$last = pos === last - } -} - -function sortByIndex(array, indexes) { - var map = {}; - for (var i = 0, n = indexes.length; i < n; i++) { - map[i] = array[i] // preserve - var j = indexes[i] - if (j in map) { - array[i] = map[j] - delete map[j] - } else { - array[i] = array[j] - } - } -} - -"sort,reverse".replace(rword, function (method) { - arrayPrototype[method] = function () { - var newArray = this.$model//这是è¦æŽ’åºçš„新数组 - var oldArray = newArray.concat() //ä¿æŒåŽŸæ¥çŠ¶æ€çš„旧数组 - var mask = Math.random() - var indexes = [] - var hasSort - ap[method].apply(newArray, arguments) //æŽ’åº - for (var i = 0, n = oldArray.length; i < n; i++) { - var neo = newArray[i] - var old = oldArray[i] - if (isEqual(neo, old)) { - indexes.push(i) - } else { - var index = oldArray.indexOf(neo) - indexes.push(index)//得到新数组的æ¯ä¸ªå…ƒç´ åœ¨æ—§æ•°ç»„对应的ä½ç½® - oldArray[index] = mask //å±è”½å·²ç»æ‰¾è¿‡çš„元素 - hasSort = true - } - } - if (hasSort) { - sortByIndex(this, indexes) - // sortByIndex(this.$proxy, indexes) - this._fire("move", indexes) - this._fire("index", 0) - } - return this - } -}) - - -/********************************************************************* - * ä¾èµ–调度系统 * - **********************************************************************/ -//检测两个对象间的ä¾èµ–关系 -var dependencyDetection = (function () { - var outerFrames = [] - var currentFrame - return { - begin: function (accessorObject) { - //accessorObject为一个拥有callback的对象 - outerFrames.push(currentFrame) - currentFrame = accessorObject - }, - end: function () { - currentFrame = outerFrames.pop() - }, - collectDependency: function (vmodel, accessor) { - if (currentFrame) { - //被dependencyDetection.begin调用 - currentFrame.callback(vmodel, accessor); - } - } - }; -})() -//将绑定对象注入到其ä¾èµ–项的订阅数组中 -var ronduplex = /^(duplex|on)$/ -avalon.injectBinding = function (data) { - var valueFn = data.evaluator - if (valueFn) { //如果是求值函数 - dependencyDetection.begin({ - callback: function (vmodel, dependency) { - injectDependency(vmodel.$events[dependency._name], data) - } - }) - try { - var value = ronduplex.test(data.type) ? data : valueFn.apply(0, data.args) - if(value === void 0){ - delete data.evaluator - } - data.handler(value, data.element, data) - } catch (e) { - //log("warning:exception throwed in [avalon.injectBinding] " + e) - delete data.evaluator - var node = data.element - if (node.nodeType === 3) { - var parent = node.parentNode - if (kernel.commentInterpolate) { - parent.replaceChild(DOC.createComment(data.value), node) - } else { - node.data = openTag + (data.oneTime ? "::" : "") + data.value + closeTag - } - } - } finally { - dependencyDetection.end() - } - } -} - -//å°†ä¾èµ–项(比它高层的访问器或构建视图刷新函数的绑定对象)注入到订阅者数组 -function injectDependency(list, data) { - if (data.oneTime) - return - if (list && avalon.Array.ensure(list, data) && data.element) { - injectDisposeQueue(data, list) - } -} - -//通知ä¾èµ–于这个访问器的订阅者更新自身 -function fireDependencies(list) { - if (list && list.length) { - if (new Date() - beginTime > 444 && typeof list[0] === "object") { - rejectDisposeQueue() - } - var args = aslice.call(arguments, 1) - for (var i = list.length, fn; fn = list[--i]; ) { - var el = fn.element - if (el && el.parentNode) { - try { - var valueFn = fn.evaluator - if (fn.$repeat) { - fn.handler.apply(fn, args) //处ç†ç›‘控数组的方法 - }else if("$repeat" in fn || !valueFn ){//如果没有eval,å…ˆeval - bindingHandlers[fn.type](fn, fn.vmodels) - } else if (fn.type !== "on") { //事件绑定åªèƒ½ç”±ç”¨æˆ·è§¦å‘,ä¸èƒ½ç”±ç¨‹åºè§¦å‘ - var value = valueFn.apply(0, fn.args || []) - fn.handler(value, el, fn) - } - } catch (e) { } - } - } - } -} -/********************************************************************* - * 定时GC回收机制 * - **********************************************************************/ -var disposeCount = 0 -var disposeQueue = avalon.$$subscribers = [] -var beginTime = new Date() -var oldInfo = {} -var uuid2Node = {} -function getUid(obj, makeID) { //IE9+,标准æµè§ˆå™¨ - if (!obj.uuid && !makeID) { - obj.uuid = ++disposeCount - uuid2Node[obj.uuid] = obj - } - return obj.uuid -} -function getNode(uuid) { - return uuid2Node[uuid] -} -//添加到回收列队中 -function injectDisposeQueue(data, list) { - var elem = data.element - if (!data.uuid) { - if (elem.nodeType !== 1) { - data.uuid = data.type + (data.pos || 0) + "-" + getUid(elem.parentNode) - } else { - data.uuid = data.name + "-" + getUid(elem) - } - } - var lists = data.lists || (data.lists = []) - avalon.Array.ensure(lists, list) - list.$uuid = list.$uuid || generateID() - if (!disposeQueue[data.uuid]) { - disposeQueue[data.uuid] = 1 - disposeQueue.push(data) - } -} - -function rejectDisposeQueue(data) { - if (avalon.optimize) - return - var i = disposeQueue.length - var n = i - var allTypes = [] - var iffishTypes = {} - var newInfo = {} - //对页é¢ä¸Šæ‰€æœ‰ç»‘定对象进行分门别类, åªæ£€æµ‹ä¸ªæ•°å‘生å˜åŒ–的类型 - while (data = disposeQueue[--i]) { - var type = data.type - if (newInfo[type]) { - newInfo[type]++ - } else { - newInfo[type] = 1 - allTypes.push(type) - } - } - var diff = false - allTypes.forEach(function (type) { - if (oldInfo[type] !== newInfo[type]) { - iffishTypes[type] = 1 - diff = true - } - }) - i = n - if (diff) { - while (data = disposeQueue[--i]) { - if (!data.element) - continue - if (iffishTypes[data.type] && shouldDispose(data.element)) { //如果它没有在DOMæ ‘ - disposeQueue.splice(i, 1) - delete disposeQueue[data.uuid] - delete uuid2Node[data.element.uuid] - var lists = data.lists - for (var k = 0, list; list = lists[k++]; ) { - avalon.Array.remove(lists, list) - avalon.Array.remove(list, data) - } - disposeData(data) - } - } - } - oldInfo = newInfo - beginTime = new Date() -} - -function disposeData(data) { - data.element = null - data.rollback && data.rollback() - for (var key in data) { - data[key] = null - } -} - -function shouldDispose(el) { - try {//IE下,如果文本节点脱离DOM树,访问parentNode会报错 - if (!el.parentNode) { - return true - } - } catch (e) { - return true - } - - return el.msRetain ? 0 : (el.nodeType === 1 ? !root.contains(el) : !avalon.contains(root, el)) -} - -/************************************************************************ - * HTML处ç†(parseHTML, innerHTML, clearHTML) * - ************************************************************************/ -// We have to close these tags to support XHTML -var tagHooks = { - area: [1, "", ""], - param: [1, "", ""], - col: [2, "", "
"], - legend: [1, "
", "
"], - option: [1, ""], - thead: [1, "", "
"], - tr: [2, "", "
"], - td: [3, "", "
"], - g: [1, '', ''], - //IE6-8在用innerHTML生æˆèŠ‚点时,ä¸èƒ½ç›´æŽ¥åˆ›å»ºno-scope元素与HTML5的新标签 - _default: W3C ? [0, "", ""] : [1, "X
", "
"] //divå¯ä»¥ä¸ç”¨é—­åˆ -} -tagHooks.th = tagHooks.td -tagHooks.optgroup = tagHooks.option -tagHooks.tbody = tagHooks.tfoot = tagHooks.colgroup = tagHooks.caption = tagHooks.thead -String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function (tag) { - tagHooks[tag] = tagHooks.g //处ç†SVG -}) -var rtagName = /<([\w:]+)/ //å–å¾—å…¶tagName -var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig -var rcreate = W3C ? /[^\d\D]/ : /(<(?:script|link|style|meta|noscript))/ig -var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"]) -var rnest = /<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/ //需è¦å¤„ç†å¥—嵌关系的标签 -var script = DOC.createElement("script") -var rhtml = /<|&#?\w+;/ -avalon.parseHTML = function (html) { - var fragment = avalonFragment.cloneNode(false) - if (typeof html !== "string") { - return fragment - } - if (!rhtml.test(html)) { - fragment.appendChild(DOC.createTextNode(html)) - return fragment - } - html = html.replace(rxhtml, "<$1>").trim() - var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(), - //å–得其标签å - wrap = tagHooks[tag] || tagHooks._default, - wrapper = cinerator, - firstChild, neo - if (!W3C) { //fix IE - html = html.replace(rcreate, "
$1") //在link style script等标签之å‰æ·»åŠ ä¸€ä¸ªè¡¥ä¸ - } - wrapper.innerHTML = wrap[1] + html + wrap[2] - var els = wrapper.getElementsByTagName("script") - if (els.length) { //使用innerHTML生æˆçš„script节点ä¸ä¼šå‘出请求与执行text属性 - for (var i = 0, el; el = els[i++]; ) { - if (scriptTypes[el.type]) { - //以å·é¾™è½¬å‡¤æ–¹å¼æ¢å¤æ‰§è¡Œè„šæœ¬åŠŸèƒ½ - neo = script.cloneNode(false) //FFä¸èƒ½çœç•¥å‚æ•° - ap.forEach.call(el.attributes, function (attr) { - if (attr && attr.specified) { - neo[attr.name] = attr.value //å¤åˆ¶å…¶å±žæ€§ - neo.setAttribute(attr.name, attr.value) - } - }) // jshint ignore:line - neo.text = el.text - el.parentNode.replaceChild(neo, el) //替æ¢èŠ‚点 - } - } - } - if (!W3C) { //fix IE - var target = wrap[1] === "X
" ? wrapper.lastChild.firstChild : wrapper.lastChild - if (target && target.tagName === "TABLE" && tag !== "tbody") { - //IE6-7å¤„ç† --> , - // --> , - // -->
- for (els = target.childNodes, i = 0; el = els[i++]; ) { - if (el.tagName === "TBODY" && !el.innerHTML) { - target.removeChild(el) - break - } - } - } - els = wrapper.getElementsByTagName("br") - var n = els.length - while (el = els[--n]) { - if (el.className === "msNoScope") { - el.parentNode.removeChild(el) - } - } - for (els = wrapper.all, i = 0; el = els[i++]; ) { //fix VML - if (isVML(el)) { - fixVML(el) - } - } - } - //移除我们为了符åˆå¥—嵌关系而添加的标签 - for (i = wrap[0]; i--; wrapper = wrapper.lastChild) { - } - while (firstChild = wrapper.firstChild) { // å°†wrapperä¸Šçš„èŠ‚ç‚¹è½¬ç§»åˆ°æ–‡æ¡£ç¢Žç‰‡ä¸Šï¼ - fragment.appendChild(firstChild) - } - return fragment -} - -function isVML(src) { - var nodeName = src.nodeName - return nodeName.toLowerCase() === nodeName && src.scopeName && src.outerText === "" -} - -function fixVML(node) { - if (node.currentStyle.behavior !== "url(#default#VML)") { - node.style.behavior = "url(#default#VML)" - node.style.display = "inline-block" - node.style.zoom = 1 //hasLayout - } -} -avalon.innerHTML = function (node, html) { - if (!W3C && (!rcreate.test(html) && !rnest.test(html))) { - try { - node.innerHTML = html - return - } catch (e) { - } - } - var a = this.parseHTML(html) - this.clearHTML(node).appendChild(a) -} -avalon.clearHTML = function (node) { - node.textContent = "" - while (node.firstChild) { - node.removeChild(node.firstChild) - } - return node -} - -/********************************************************************* - * avalon的原型方法定义区 * - **********************************************************************/ - -function hyphen(target) { - //转æ¢ä¸ºè¿žå­—符线风格 - return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase() -} - -function camelize(target) { - //æå‰åˆ¤æ–­ï¼Œæ高getStyle等的效率 - if (!target || target.indexOf("-") < 0 && target.indexOf("_") < 0) { - return target - } - //转æ¢ä¸ºé©¼å³°é£Žæ ¼ - return target.replace(/[-_][^-_]/g, function(match) { - return match.charAt(1).toUpperCase() - }) -} - -var fakeClassListMethods = { - _toString: function() { - var node = this.node - var cls = node.className - var str = typeof cls === "string" ? cls : cls.baseVal - return str.split(/\s+/).join(" ") - }, - _contains: function(cls) { - return (" " + this + " ").indexOf(" " + cls + " ") > -1 - }, - _add: function(cls) { - if (!this.contains(cls)) { - this._set(this + " " + cls) - } - }, - _remove: function(cls) { - this._set((" " + this + " ").replace(" " + cls + " ", " ")) - }, - __set: function(cls) { - cls = cls.trim() - var node = this.node - if (rsvg.test(node)) { - //SVG元素的className是一个对象 SVGAnimatedString { baseVal="", animVal=""},åªèƒ½é€šè¿‡set/getAttributeæ“作 - node.setAttribute("class", cls) - } else { - node.className = cls - } - } //toggle存在版本差异,因此ä¸ä½¿ç”¨å®ƒ -} - - function fakeClassList(node) { - if (!("classList" in node)) { - node.classList = { - node: node - } - for (var k in fakeClassListMethods) { - node.classList[k.slice(1)] = fakeClassListMethods[k] - } - } - return node.classList - } - - - "add,remove".replace(rword, function(method) { - avalon.fn[method + "Class"] = function(cls) { - var el = this[0] - //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26 - if (cls && typeof cls === "string" && el && el.nodeType === 1) { - cls.replace(/\S+/g, function(c) { - fakeClassList(el)[method](c) - }) - } - return this - } - }) - avalon.fn.mix({ - hasClass: function(cls) { - var el = this[0] || {} - return el.nodeType === 1 && fakeClassList(el).contains(cls) - }, - toggleClass: function(value, stateVal) { - var className, i = 0 - var classNames = String(value).split(/\s+/) - var isBool = typeof stateVal === "boolean" - while ((className = classNames[i++])) { - var state = isBool ? stateVal : !this.hasClass(className) - this[state ? "addClass" : "removeClass"](className) - } - return this - }, - attr: function(name, value) { - if (arguments.length === 2) { - this[0].setAttribute(name, value) - return this - } else { - return this[0].getAttribute(name) - } - }, - data: function(name, value) { - name = "data-" + hyphen(name || "") - switch (arguments.length) { - case 2: - this.attr(name, value) - return this - case 1: - var val = this.attr(name) - return parseData(val) - case 0: - var ret = {} - ap.forEach.call(this[0].attributes, function(attr) { - if (attr) { - name = attr.name - if (!name.indexOf("data-")) { - name = camelize(name.slice(5)) - ret[name] = parseData(attr.value) - } - } - }) - return ret - } - }, - removeData: function(name) { - name = "data-" + hyphen(name) - this[0].removeAttribute(name) - return this - }, - css: function(name, value) { - if (avalon.isPlainObject(name)) { - for (var i in name) { - avalon.css(this, i, name[i]) - } - } else { - var ret = avalon.css(this, name, value) - } - return ret !== void 0 ? ret : this - }, - position: function() { - var offsetParent, offset, - elem = this[0], - parentOffset = { - top: 0, - left: 0 - } - if (!elem) { - return - } - if (this.css("position") === "fixed") { - offset = elem.getBoundingClientRect() - } else { - offsetParent = this.offsetParent() //得到真正的offsetParent - offset = this.offset() // 得到正确的offsetParent - if (offsetParent[0].tagName !== "HTML") { - parentOffset = offsetParent.offset() - } - parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true) - parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true) - - // Subtract offsetParent scroll positions - parentOffset.top -= offsetParent.scrollTop() - parentOffset.left -= offsetParent.scrollLeft() - } - return { - top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true), - left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true) - } - }, - offsetParent: function() { - var offsetParent = this[0].offsetParent - while (offsetParent && avalon.css(offsetParent, "position") === "static") { - offsetParent = offsetParent.offsetParent; - } - return avalon(offsetParent || root) - }, - bind: function(type, fn, phase) { - if (this[0]) { //此方法ä¸ä¼šé“¾ - return avalon.bind(this[0], type, fn, phase) - } - }, - unbind: function(type, fn, phase) { - if (this[0]) { - avalon.unbind(this[0], type, fn, phase) - } - return this - }, - val: function(value) { - var node = this[0] - if (node && node.nodeType === 1) { - var get = arguments.length === 0 - var access = get ? ":get" : ":set" - var fn = valHooks[getValType(node) + access] - if (fn) { - var val = fn(node, value) - } else if (get) { - return (node.value || "").replace(/\r/g, "") - } else { - node.value = value - } - } - return get ? val : this - } - }) - - function parseData(data) { - try { - if (typeof data === "object") - return data - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? avalon.parseJSON(data) : data - } catch (e) {} - return data - } -var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g -avalon.parseJSON = window.JSON ? JSON.parse : function(data) { - if (typeof data === "string") { - data = data.trim(); - if (data) { - if (rvalidchars.test(data.replace(rvalidescape, "@") - .replace(rvalidtokens, "]") - .replace(rvalidbraces, ""))) { - return (new Function("return " + data))() // jshint ignore:line - } - } - avalon.error("Invalid JSON: " + data) - } - return data -} - -//生æˆavalon.fn.scrollLeft, avalon.fn.scrollTop方法 -avalon.each({ - scrollLeft: "pageXOffset", - scrollTop: "pageYOffset" -}, function(method, prop) { - avalon.fn[method] = function(val) { - var node = this[0] || {}, win = getWindow(node), - top = method === "scrollTop" - if (!arguments.length) { - return win ? (prop in win) ? win[prop] : root[method] : node[method] - } else { - if (win) { - win.scrollTo(!top ? val : avalon(win).scrollLeft(), top ? val : avalon(win).scrollTop()) - } else { - node[method] = val - } - } - } -}) - -function getWindow(node) { - return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView || node.parentWindow : false; -} -//=============================css相关======================= -var cssHooks = avalon.cssHooks = {} -var prefixes = ["", "-webkit-", "-o-", "-moz-", "-ms-"] -var cssMap = { - "float": W3C ? "cssFloat" : "styleFloat" -} -avalon.cssNumber = oneObject("columnCount,order,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom") - -avalon.cssName = function(name, host, camelCase) { - if (cssMap[name]) { - return cssMap[name] - } - host = host || root.style - for (var i = 0, n = prefixes.length; i < n; i++) { - camelCase = camelize(prefixes[i] + name) - if (camelCase in host) { - return (cssMap[name] = camelCase) - } - } - return null -} -cssHooks["@:set"] = function(node, name, value) { - try { //node.style.width = NaN;node.style.width = "xxxxxxx";node.style.width = undefine 在旧å¼IE下会抛异常 - node.style[name] = value - } catch (e) {} -} -if (window.getComputedStyle) { - cssHooks["@:get"] = function(node, name) { - if (!node || !node.style) { - throw new Error("getComputedStyleè¦æ±‚传入一个节点 " + node) - } - var ret, styles = getComputedStyle(node, null) - if (styles) { - ret = name === "filter" ? styles.getPropertyValue(name) : styles[name] - if (ret === "") { - ret = node.style[name] //其他æµè§ˆå™¨éœ€è¦æˆ‘们手动å–内è”æ ·å¼ - } - } - return ret - } - cssHooks["opacity:get"] = function(node) { - var ret = cssHooks["@:get"](node, "opacity") - return ret === "" ? "1" : ret - } -} else { - var rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i - var rposition = /^(top|right|bottom|left)$/ - var ralpha = /alpha\([^)]*\)/i - var ie8 = !! window.XDomainRequest - var salpha = "DXImageTransform.Microsoft.Alpha" - var border = { - thin: ie8 ? '1px' : '2px', - medium: ie8 ? '3px' : '4px', - thick: ie8 ? '5px' : '6px' - } - cssHooks["@:get"] = function(node, name) { - //å–得精确值,ä¸è¿‡å®ƒæœ‰å¯èƒ½æ˜¯å¸¦em,pc,mm,pt,%ç­‰å•ä½ - var currentStyle = node.currentStyle - var ret = currentStyle[name] - if ((rnumnonpx.test(ret) && !rposition.test(ret))) { - //①,ä¿å­˜åŽŸæœ‰çš„style.left, runtimeStyle.left, - var style = node.style, - left = style.left, - rsLeft = node.runtimeStyle.left - //②由于③处的style.left = xxx会影å“到currentStyle.left, - //因此把它currentStyle.left放到runtimeStyle.left, - //runtimeStyle.left拥有最高优先级,ä¸ä¼šstyle.leftå½±å“ - node.runtimeStyle.left = currentStyle.left - //③将精确值赋给到style.left,然åŽé€šè¿‡IEçš„å¦ä¸€ä¸ªç§æœ‰å±žæ€§ style.pixelLeft - //得到å•ä½ä¸ºpx的结果;fontSize的分支è§http://bugs.jquery.com/ticket/760 - style.left = name === 'fontSize' ? '1em' : (ret || 0) - ret = style.pixelLeft + "px" - //④还原 style.left,runtimeStyle.left - style.left = left - node.runtimeStyle.left = rsLeft - } - if (ret === "medium") { - name = name.replace("Width", "Style") - //border width 默认值为medium,å³ä½¿å…¶ä¸º0" - if (currentStyle[name] === "none") { - ret = "0px" - } - } - return ret === "" ? "auto" : border[ret] || ret - } - cssHooks["opacity:set"] = function(node, name, value) { - var style = node.style - var opacity = isFinite(value) && value <= 1 ? "alpha(opacity=" + value * 100 + ")" : "" - var filter = style.filter || ""; - style.zoom = 1 - //ä¸èƒ½ä½¿ç”¨ä»¥ä¸‹æ–¹å¼è®¾ç½®é€æ˜Žåº¦ - //node.filters.alpha.opacity = value * 100 - style.filter = (ralpha.test(filter) ? - filter.replace(ralpha, opacity) : - filter + " " + opacity).trim() - if (!style.filter) { - style.removeAttribute("filter") - } - } - cssHooks["opacity:get"] = function(node) { - //这是最快的获å–IEé€æ˜Žå€¼çš„æ–¹å¼ï¼Œä¸éœ€è¦åŠ¨ç”¨æ­£åˆ™äº†ï¼ - var alpha = node.filters.alpha || node.filters[salpha], - op = alpha && alpha.enabled ? alpha.opacity : 100 - return (op / 100) + "" //ç¡®ä¿è¿”回的是字符串 - } -} - -"top,left".replace(rword, function(name) { - cssHooks[name + ":get"] = function(node) { - var computed = cssHooks["@:get"](node, name) - return /px$/.test(computed) ? computed : - avalon(node).position()[name] + "px" - } -}) - -var cssShow = { - position: "absolute", - visibility: "hidden", - display: "block" -} - -var rdisplayswap = /^(none|table(?!-c[ea]).+)/ - - function showHidden(node, array) { - //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html - if (node.offsetWidth <= 0) { //opera.offsetWidthå¯èƒ½å°äºŽ0 - if (rdisplayswap.test(cssHooks["@:get"](node, "display"))) { - var obj = { - node: node - } - for (var name in cssShow) { - obj[name] = node.style[name] - node.style[name] = cssShow[name] - } - array.push(obj) - } - var parent = node.parentNode - if (parent && parent.nodeType === 1) { - showHidden(parent, array) - } - } - } - "Width,Height".replace(rword, function(name) { //fix 481 - var method = name.toLowerCase(), - clientProp = "client" + name, - scrollProp = "scroll" + name, - offsetProp = "offset" + name - cssHooks[method + ":get"] = function(node, which, override) { - var boxSizing = -4 - if (typeof override === "number") { - boxSizing = override - } - which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"] - var ret = node[offsetProp] // border-box 0 - if (boxSizing === 2) { // margin-box 2 - return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true) - } - if (boxSizing < 0) { // padding-box -2 - ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true) - } - if (boxSizing === -4) { // content-box -4 - ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true) - } - return ret - } - cssHooks[method + "&get"] = function(node) { - var hidden = []; - showHidden(node, hidden); - var val = cssHooks[method + ":get"](node) - for (var i = 0, obj; obj = hidden[i++];) { - node = obj.node - for (var n in obj) { - if (typeof obj[n] === "string") { - node.style[n] = obj[n] - } - } - } - return val; - } - avalon.fn[method] = function(value) { //会忽视其display - var node = this[0] - if (arguments.length === 0) { - if (node.setTimeout) { //å–得窗å£å°ºå¯¸,IE9åŽå¯ä»¥ç”¨node.innerWidth /innerHeight代替 - return node["inner" + name] || node.document.documentElement[clientProp] - } - if (node.nodeType === 9) { //å–得页é¢å°ºå¯¸ - var doc = node.documentElement - //FF chrome html.scrollHeight< body.scrollHeight - //IE æ ‡å‡†æ¨¡å¼ : html.scrollHeight> body.scrollHeight - //IE æ€ªå¼‚æ¨¡å¼ : html.scrollHeight 最大等于å¯è§†çª—å£å¤šä¸€ç‚¹ï¼Ÿ - return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp]) - } - return cssHooks[method + "&get"](node) - } else { - return this.css(method, value) - } - } - avalon.fn["inner" + name] = function() { - return cssHooks[method + ":get"](this[0], void 0, -2) - } - avalon.fn["outer" + name] = function(includeMargin) { - return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0) - } - }) - avalon.fn.offset = function() { //å–å¾—è·ç¦»é¡µé¢å·¦å³è§’çš„åæ ‡ - var node = this[0], - box = { - left: 0, - top: 0 - } - if (!node || !node.tagName || !node.ownerDocument) { - return box - } - var doc = node.ownerDocument, - body = doc.body, - root = doc.documentElement, - win = doc.defaultView || doc.parentWindow - if (!avalon.contains(root, node)) { - return box - } - //http://hkom.blog1.fc2.com/?mode=m&no=750 bodyçš„å移é‡æ˜¯ä¸åŒ…å«marginçš„ - //我们å¯ä»¥é€šè¿‡getBoundingClientRectæ¥èŽ·å¾—元素相对于clientçš„rect. - //http://msdn.microsoft.com/en-us/library/ms536433.aspx - if (node.getBoundingClientRect) { - box = node.getBoundingClientRect() // BlackBerry 5, iOS 3 (original iPhone) - } - //chrome/IE6: body.scrollTop, firefox/other: root.scrollTop - var clientTop = root.clientTop || body.clientTop, - clientLeft = root.clientLeft || body.clientLeft, - scrollTop = Math.max(win.pageYOffset || 0, root.scrollTop, body.scrollTop), - scrollLeft = Math.max(win.pageXOffset || 0, root.scrollLeft, body.scrollLeft) - // 把滚动è·ç¦»åŠ åˆ°left,top中去。 - // IE一些版本中会自动为HTML元素加上2pxçš„border,我们需è¦åŽ»æŽ‰å®ƒ - // http://msdn.microsoft.com/en-us/library/ms533564(VS.85).aspx - return { - top: box.top + scrollTop - clientTop, - left: box.left + scrollLeft - clientLeft - } - } - - //==================================val相关============================ - - function getValType(elem) { - var ret = elem.tagName.toLowerCase() - return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret - } -var roption = /^]+))?)*\s+value[\s=]/i -var valHooks = { - "option:get": IEVersion ? function(node) { - //在IE11åŠW3C,如果没有指定value,那么node.value默认为node.text(存在trim作),但IE9-10则是å–innerHTML(没trimæ“作) - //specified并ä¸å¯é ï¼Œå› æ­¤é€šè¿‡åˆ†æžouterHTML判定用户有没有显示定义value - return roption.test(node.outerHTML) ? node.value : node.text.trim() - } : function(node) { - return node.value - }, - "select:get": function(node, value) { - var option, options = node.options, - index = node.selectedIndex, - getter = valHooks["option:get"], - one = node.type === "select-one" || index < 0, - values = one ? null : [], - max = one ? index + 1 : options.length, - i = index < 0 ? max : one ? index : 0 - for (; i < max; i++) { - option = options[i] - //æ—§å¼IE在resetåŽä¸ä¼šæ”¹å˜selected,需è¦æ”¹ç”¨i === index判定 - //我们过滤所有disabledçš„option元素,但在safari5下,如果设置select为disable,那么其所有孩å­éƒ½disable - //因此当一个元素为disable,需è¦æ£€æµ‹å…¶æ˜¯å¦æ˜¾å¼è®¾ç½®äº†disableåŠå…¶çˆ¶èŠ‚点的disable情况 - if ((option.selected || i === index) && !option.disabled) { - value = getter(option) - if (one) { - return value - } - //收集所有selected值组æˆæ•°ç»„返回 - values.push(value) - } - } - return values - }, - "select:set": function(node, values, optionSet) { - values = [].concat(values) //强制转æ¢ä¸ºæ•°ç»„ - var getter = valHooks["option:get"] - for (var i = 0, el; el = node.options[i++];) { - if ((el.selected = values.indexOf(getter(el)) > -1)) { - optionSet = true - } - } - if (!optionSet) { - node.selectedIndex = -1 - } - } -} - -/********************************************************************* - * 编译系统 * - **********************************************************************/ -var meta = { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"': '\\"', - '\\': '\\\\' -} -var quote = window.JSON && JSON.stringify || function(str) { - return '"' + str.replace(/[\\\"\x00-\x1f]/g, function(a) { - var c = meta[a]; - return typeof c === 'string' ? c : - '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' -} - -var keywords = [ - "break,case,catch,continue,debugger,default,delete,do,else,false", - "finally,for,function,if,in,instanceof,new,null,return,switch,this", - "throw,true,try,typeof,var,void,while,with", /* 关键字*/ - "abstract,boolean,byte,char,class,const,double,enum,export,extends", - "final,float,goto,implements,import,int,interface,long,native", - "package,private,protected,public,short,static,super,synchronized", - "throws,transient,volatile", /*ä¿ç•™å­—*/ - "arguments,let,yield,undefined" /* ECMA 5 - use strict*/].join(",") -var rrexpstr = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g -var rsplit = /[^\w$]+/g -var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g') -var rnumber = /\b\d[^,]*/g -var rcomma = /^,+|,+$/g -var variablePool = new Cache(512) -var getVariables = function (code) { - var key = "," + code.trim() - var ret = variablePool.get(key) - if (ret) { - return ret - } - var match = code - .replace(rrexpstr, "") - .replace(rsplit, ",") - .replace(rkeywords, "") - .replace(rnumber, "") - .replace(rcomma, "") - .split(/^$|,+/) - return variablePool.put(key, uniqSet(match)) -} -/*添加赋值语å¥*/ - -function addAssign(vars, scope, name, data) { - var ret = [], - prefix = " = " + name + "." - for (var i = vars.length, prop; prop = vars[--i]; ) { - if (scope.hasOwnProperty(prop)) { - ret.push(prop + prefix + prop) - data.vars.push(prop) - if (data.type === "duplex") { - vars.get = name + "." + prop - } - vars.splice(i, 1) - } - } - return ret -} - -function uniqSet(array) { - var ret = [], - unique = {} - for (var i = 0; i < array.length; i++) { - var el = array[i] - var id = el && typeof el.$id === "string" ? el.$id : el - if (!unique[id]) { - unique[id] = ret.push(el) - } - } - return ret -} -//缓存求值函数,以便多次利用 -var evaluatorPool = new Cache(128) -//å–得求值函数åŠå…¶ä¼ å‚ -var rduplex = /\w\[.*\]|\w\.\w/ -var rproxy = /(\$proxy\$[a-z]+)\d+$/ -var rthimRightParentheses = /\)\s*$/ -var rthimOtherParentheses = /\)\s*\|/g -var rquoteFilterName = /\|\s*([$\w]+)/g -var rpatchBracket = /"\s*\["/g -var rthimLeftParentheses = /"\s*\(/g -function parseFilter(val, filters) { - filters = filters - .replace(rthimRightParentheses, "")//处ç†æœ€åŽçš„å°æ‹¬å· - .replace(rthimOtherParentheses, function () {//处ç†å…¶ä»–å°æ‹¬å· - return "],|" - }) - .replace(rquoteFilterName, function (a, b) { //处ç†|åŠå®ƒåŽé¢çš„过滤器的åå­— - return "[" + quote(b) - }) - .replace(rpatchBracket, function () { - return '"],["' - }) - .replace(rthimLeftParentheses, function () { - return '",' - }) + "]" - return "return avalon.filters.$filter(" + val + ", " + filters + ")" -} - -function parseExpr(code, scopes, data) { - var dataType = data.type - var filters = data.filters || "" - var exprId = scopes.map(function (el) { - return String(el.$id).replace(rproxy, "$1") - }) + code + dataType + filters - var vars = getVariables(code).concat(), - assigns = [], - names = [], - args = [], - prefix = "" - //args 是一个对象数组, names 是将è¦ç”Ÿæˆçš„求值函数的å‚æ•° - scopes = uniqSet(scopes) - data.vars = [] - for (var i = 0, sn = scopes.length; i < sn; i++) { - if (vars.length) { - var name = "vm" + expose + "_" + i - names.push(name) - args.push(scopes[i]) - assigns.push.apply(assigns, addAssign(vars, scopes[i], name, data)) - } - } - if (!assigns.length && dataType === "duplex") { - return - } - if (dataType !== "duplex" && (code.indexOf("||") > -1 || code.indexOf("&&") > -1)) { - //https://github.com/RubyLouvre/avalon/issues/583 - data.vars.forEach(function (v) { - var reg = new RegExp("\\b" + v + "(?:\\.\\w+|\\[\\w+\\])+", "ig") - code = code.replace(reg, function (_) { - var c = _.charAt(v.length) - var r = IEVersion ? code.slice(arguments[1] + _.length) : RegExp.rightContext - var method = /^\s*\(/.test(r) - if (c === "." || c === "[" || method) {//比如v为aa,我们åªåŒ¹é…aa.bb,aa[cc],ä¸åŒ¹é…aaa.xxx - var name = "var" + String(Math.random()).replace(/^0\./, "") - if (method) {//array.size() - var array = _.split(".") - if (array.length > 2) { - var last = array.pop() - assigns.push(name + " = " + array.join(".")) - return name + "." + last - } else { - return _ - } - } - assigns.push(name + " = " + _) - return name - } else { - return _ - } - }) - }) - } - //---------------args---------------- - data.args = args - //---------------cache---------------- - delete data.vars - var fn = evaluatorPool.get(exprId) //直接从缓存,å…å¾—é‡å¤ç”Ÿæˆ - if (fn) { - data.evaluator = fn - return - } - prefix = assigns.join(", ") - if (prefix) { - prefix = "var " + prefix - } - if (/\S/.test(filters)) { //文本绑定,åŒå·¥ç»‘定æ‰æœ‰è¿‡æ»¤å™¨ - if (!/text|html/.test(data.type)) { - throw Error("ms-" + data.type + "ä¸æ”¯æŒè¿‡æ»¤å™¨") - } - code = "\nvar ret" + expose + " = " + code + ";\r\n" - code += parseFilter("ret" + expose, filters) - } else if (dataType === "duplex") { //åŒå·¥ç»‘定 - var _body = "'use strict';\nreturn function(vvv){\n\t" + - prefix + - ";\n\tif(!arguments.length){\n\t\treturn " + - code + - "\n\t}\n\t" + (!rduplex.test(code) ? vars.get : code) + - "= vvv;\n} " - try { - fn = Function.apply(noop, names.concat(_body)) - data.evaluator = evaluatorPool.put(exprId, fn) - } catch (e) { - log("debug: parse error," + e.message) - } - return - } else if (dataType === "on") { //事件绑定 - if (code.indexOf("(") === -1) { - code += ".call(this, $event)" - } else { - code = code.replace("(", ".call(this,") - } - names.push("$event") - code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需è¦Function("return ;") - var lastIndex = code.lastIndexOf("\nreturn") - var header = code.slice(0, lastIndex) - var footer = code.slice(lastIndex) - code = header + "\n" + footer - } else { //其他绑定 - code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需è¦Function("return ;") - } - try { - fn = Function.apply(noop, names.concat("'use strict';\n" + prefix + code)) - data.evaluator = evaluatorPool.put(exprId, fn) - } catch (e) { - log("debug: parse error," + e.message) - } finally { - vars = assigns = names = null //释放内存 - } -} - - -//parseExprçš„æ™ºèƒ½å¼•ç”¨ä»£ç† - -function parseExprProxy(code, scopes, data, tokens, noRegister) { - if (Array.isArray(tokens)) { - code = tokens.map(function (el) { - return el.expr ? "(" + el.value + ")" : quote(el.value) - }).join(" + ") - } - parseExpr(code, scopes, data) - if (data.evaluator && !noRegister) { - data.handler = bindingExecutors[data.handlerName || data.type] - //方便调试 - //这里éžå¸¸é‡è¦,我们通过判定视图刷新函数的element是å¦åœ¨DOM树决定 - //将它移出订阅者列表 - avalon.injectBinding(data) - } -} -avalon.parseExprProxy = parseExprProxy -/********************************************************************* - * 扫æ系统 * - **********************************************************************/ - -avalon.scan = function(elem, vmodel) { - elem = elem || root - var vmodels = vmodel ? [].concat(vmodel) : [] - scanTag(elem, vmodels) -} - -//http://www.w3.org/TR/html5/syntax.html#void-elements -var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase()) - -function checkScan(elem, callback, innerHTML) { - var id = setTimeout(function() { - var currHTML = elem.innerHTML - clearTimeout(id) - if (currHTML === innerHTML) { - callback() - } else { - checkScan(elem, callback, currHTML) - } - }) -} - - -function createSignalTower(elem, vmodel) { - var id = elem.getAttribute("avalonctrl") || vmodel.$id - elem.setAttribute("avalonctrl", id) - vmodel.$events.expr = elem.tagName + '[avalonctrl="' + id + '"]' -} - -var getBindingCallback = function(elem, name, vmodels) { - var callback = elem.getAttribute(name) - if (callback) { - for (var i = 0, vm; vm = vmodels[i++]; ) { - if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") { - return vm[callback] - } - } - } -} - -function executeBindings(bindings, vmodels) { - for (var i = 0, data; data = bindings[i++]; ) { - data.vmodels = vmodels - bindingHandlers[data.type](data, vmodels) - if (data.evaluator && data.element && data.element.nodeType === 1) { //移除数æ®ç»‘å®šï¼Œé˜²æ­¢è¢«äºŒæ¬¡è§£æž - //chrome使用removeAttributeNode移除ä¸å­˜åœ¨çš„特性节点时会报错 https://github.com/RubyLouvre/avalon/issues/99 - data.element.removeAttribute(data.name) - } - } - bindings.length = 0 -} - -//https://github.com/RubyLouvre/avalon/issues/636 -var mergeTextNodes = IEVersion && window.MutationObserver ? function (elem) { - var node = elem.firstChild, text - while (node) { - var aaa = node.nextSibling - if (node.nodeType === 3) { - if (text) { - text.nodeValue += node.nodeValue - elem.removeChild(node) - } else { - text = node - } - } else { - text = null - } - node = aaa - } -} : 0 -var roneTime = /^\s*::/ -var rmsAttr = /ms-(\w+)-?(.*)/ -var priorityMap = { - "if": 10, - "repeat": 90, - "data": 100, - "widget": 110, - "each": 1400, - "with": 1500, - "duplex": 2000, - "on": 3000 -} - -var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit") -var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled") -function bindingSorter(a, b) { - return a.priority - b.priority -} - -function scanAttr(elem, vmodels, match) { - var scanNode = true - if (vmodels.length) { - var attributes = getAttributes ? getAttributes(elem) : elem.attributes - var bindings = [] - var fixAttrs = [] - var msData = {} - for (var i = 0, attr; attr = attributes[i++]; ) { - if (attr.specified) { - if (match = attr.name.match(rmsAttr)) { - //如果是以指定å‰ç¼€å‘½åçš„ - var type = match[1] - var param = match[2] || "" - var value = attr.value - var name = attr.name - if (events[type]) { - param = type - type = "on" - } else if (obsoleteAttrs[type]) { - if (type === "enabled") {//åƒæŽ‰ms-enabled绑定,用ms-disabled代替 - log("warning!ms-enabled或ms-attr-enabledå·²ç»è¢«åºŸå¼ƒ") - type = "disabled" - value = "!(" + value + ")" - } - param = type - type = "attr" - name = "ms-" + type + "-"+ param - fixAttrs.push([attr.name, name, value]) - } - msData[name] = value - if (typeof bindingHandlers[type] === "function") { - var newValue = value.replace(roneTime, "") - var oneTime = value !== newValue - var binding = { - type: type, - param: param, - element: elem, - name: name, - value: newValue, - oneTime: oneTime, - uuid: name+"-"+getUid(elem), - //chrome与firefox下Number(param)得到的值ä¸ä¸€æ · #855 - priority: (priorityMap[type] || type.charCodeAt(0) * 10 )+ (Number(param.replace(/\D/g, "")) || 0) - } - if (type === "html" || type === "text") { - var token = getToken(value) - avalon.mix(binding, token) - binding.filters = binding.filters.replace(rhasHtml, function () { - binding.type = "html" - binding.group = 1 - return "" - })// jshint ignore:line - } else if (type === "duplex") { - var hasDuplex = name - } else if (name === "ms-if-loop") { - binding.priority += 100 - } - bindings.push(binding) - if (type === "widget") { - elem.msData = elem.msData || msData - } - } - } - } - } - if (bindings.length) { - bindings.sort(bindingSorter) - fixAttrs.forEach(function (arr) { - log("warning!请改用" + arr[1] + "代替" + arr[0] + "!") - elem.removeAttribute(arr[0]) - elem.setAttribute(arr[1], arr[2]) - }) - //http://bugs.jquery.com/ticket/7071 - //在IE下对VML读å–type属性,会让此元素所有属性都å˜æˆ - if (hasDuplex) { - if (msData["ms-attr-checked"]) { - log("warning!一个控件ä¸èƒ½åŒæ—¶å®šä¹‰ms-attr-checked与" + hasDuplex) - } - if (msData["ms-attr-value"]) { - log("warning!一个控件ä¸èƒ½åŒæ—¶å®šä¹‰ms-attr-value与" + hasDuplex) - } - } - for (i = 0; binding = bindings[i]; i++) { - type = binding.type - if (rnoscanAttrBinding.test(type)) { - return executeBindings(bindings.slice(0, i + 1), vmodels) - } else if (scanNode) { - scanNode = !rnoscanNodeBinding.test(type) - } - } - executeBindings(bindings, vmodels) - } - } - if (scanNode && !stopScan[elem.tagName] && rbind.test(elem.innerHTML.replace(rlt, "<").replace(rgt, ">"))) { - mergeTextNodes && mergeTextNodes(elem) - scanNodeList(elem, vmodels) //扫æå­å­™å…ƒç´  - } -} -var rnoscanAttrBinding = /^if|widget|repeat$/ -var rnoscanNodeBinding = /^each|with|html|include$/ -//IE67下,在循环绑定中,一个节点如果是通过cloneNode得到,自定义属性的specified为false,无法进入里é¢çš„分支, -//但如果我们去掉scanAttr中的attr.specified检测,一个元素会有80+个特性节点(因为它ä¸åŒºåˆ†å›ºæœ‰å±žæ€§ä¸Žè‡ªå®šä¹‰å±žæ€§ï¼‰ï¼Œå¾ˆå®¹æ˜“å¡æ­»é¡µé¢ -if (!"1" [0]) { - var attrPool = new Cache(512) - var rattrs = /\s+(ms-[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g, - rquote = /^['"]/, - rtag = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/i, - ramp = /&/g - //IE6-8解æžHTML5新标签,会将它分解两个元素节点与一个文本节点 - //
ddd
- // window.onload = function() { - // var body = document.body - // for (var i = 0, el; el = body.children[i++]; ) { - // avalon.log(el.outerHTML) - // } - // } - //ä¾æ¬¡è¾“出
,
- var getAttributes = function (elem) { - var html = elem.outerHTML - //处ç†IE6-8解æžHTML5新标签的情况,åŠ
ç­‰åŠé—­åˆæ ‡ç­¾outerHTML为空的情况 - if (html.slice(0, 2) === " ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100) - //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)åž«åŽ - var a = elem.getAttribute("ms-skip") - //#360 在旧å¼IE中 Object标签在引入Flash等资æºæ—¶,å¯èƒ½å‡ºçŽ°æ²¡æœ‰getAttributeNode,innerHTML的情形 - if (!elem.getAttributeNode) { - return log("warning " + elem.tagName + " no getAttributeNode method") - } - var b = elem.getAttributeNode("ms-important") - var c = elem.getAttributeNode("ms-controller") - if (typeof a === "string") { - return - } else if (node = b || c) { - var newVmodel = avalon.vmodels[node.value] - if (!newVmodel) { - return - } - //ms-importantä¸åŒ…å«çˆ¶VM,ms-controller相å - vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels) - var name = node.name - elem.removeAttribute(name) //removeAttributeNodeä¸ä¼šåˆ·æ–°[ms-controller]æ ·å¼è§„则 - avalon(elem).removeClass(name) - createSignalTower(elem, newVmodel) - } - scanAttr(elem, vmodels) //扫æ特性节点 -} -var rhasHtml = /\|\s*html(?:\b|$)/, - r11a = /\|\|/g, - rlt = /</g, - rgt = />/g, - rstringLiteral = /(['"])(\\\1|.)+?\1/g -function getToken(value) { - if (value.indexOf("|") > 0) { - var scapegoat = value.replace(rstringLiteral, function (_) { - return Array(_.length + 1).join("1")// jshint ignore:line - }) - var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或 - if (index > -1) { - return { - filters: value.slice(index), - value: value.slice(0, index), - expr: true - } - } - } - return { - value: value, - filters: "", - expr: true - } -} - -function scanExpr(str) { - var tokens = [], - value, start = 0, - stop - do { - stop = str.indexOf(openTag, start) - if (stop === -1) { - break - } - value = str.slice(start, stop) - if (value) { // {{ 左边的文本 - tokens.push({ - value: value, - filters: "", - expr: false - }) - } - start = stop + openTag.length - stop = str.indexOf(closeTag, start) - if (stop === -1) { - break - } - value = str.slice(start, stop) - if (value) { //处ç†{{ }}æ’å€¼è¡¨è¾¾å¼ - tokens.push(getToken(value, start)) - } - start = stop + closeTag.length - } while (1) - value = str.slice(start) - if (value) { //}} å³è¾¹çš„文本 - tokens.push({ - value: value, - expr: false, - filters: "" - }) - } - return tokens -} - -function scanText(textNode, vmodels, index) { - var bindings = [] - tokens = scanExpr(textNode.data) - if (tokens.length) { - for (var i = 0; token = tokens[i++]; ) { - var node = DOC.createTextNode(token.value) //将文本转æ¢ä¸ºæ–‡æœ¬èŠ‚点,并替æ¢åŽŸæ¥çš„文本节点 - if (token.expr) { - token.value = token.value.replace(roneTime, function () { - token.oneTime = true - return "" - }) - token.type = "text" - token.element = node - token.filters = token.filters.replace(rhasHtml, function (a, b,c) { - token.type = "html" - return "" - })// jshint ignore:line - token.pos = index * 1000 + i - bindings.push(token) //收集带有æ’值表达å¼çš„文本 - } - avalonFragment.appendChild(node) - } - textNode.parentNode.replaceChild(avalonFragment, textNode) - if (bindings.length) - executeBindings(bindings, vmodels) - } -} - -var bools = ["autofocus,autoplay,async,allowTransparency,checked,controls", - "declare,disabled,defer,defaultChecked,defaultSelected", - "contentEditable,isMap,loop,multiple,noHref,noResize,noShade", - "open,readOnly,selected" -].join(",") -var boolMap = {} -bools.replace(rword, function(name) { - boolMap[name.toLowerCase()] = name -}) - -var propMap = { //属性å映射 - "accept-charset": "acceptCharset", - "char": "ch", - "charoff": "chOff", - "class": "className", - "for": "htmlFor", - "http-equiv": "httpEquiv" -} - -var anomaly = ["accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan", - "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight", - "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign" -].join(",") -anomaly.replace(rword, function(name) { - propMap[name.toLowerCase()] = name -}) - -var rnoscripts = /(?:[\s\S]+?)<\/noscript>/img -var rnoscriptText = /([\s\S]+?)<\/noscript>/im - -var getXHR = function() { - return new(window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP") // jshint ignore:line -} - -var templatePool = avalon.templateCache = {} - -bindingHandlers.attr = function(data, vmodels) { - var text = data.value.trim(), - simple = true - if (text.indexOf(openTag) > -1 && text.indexOf(closeTag) > 2) { - simple = false - if (rexpr.test(text) && RegExp.rightContext === "" && RegExp.leftContext === "") { - simple = true - text = RegExp.$1 - } - } - if (data.type === "include") { - var elem = data.element - data.includeRendered = getBindingCallback(elem, "data-include-rendered", vmodels) - data.includeLoaded = getBindingCallback(elem, "data-include-loaded", vmodels) - var outer = data.includeReplace = !! avalon(elem).data("includeReplace") - if (avalon(elem).data("includeCache")) { - data.templateCache = {} - } - data.startInclude = DOC.createComment("ms-include") - data.endInclude = DOC.createComment("ms-include-end") - if (outer) { - data.element = data.startInclude - elem.parentNode.insertBefore(data.startInclude, elem) - elem.parentNode.insertBefore(data.endInclude, elem.nextSibling) - } else { - elem.insertBefore(data.startInclude, elem.firstChild) - elem.appendChild(data.endInclude) - } - } - data.handlerName = "attr" //handleName用于处ç†å¤šç§ç»‘定共用åŒä¸€ç§bindingExecutor的情况 - parseExprProxy(text, vmodels, data, (simple ? 0 : scanExpr(data.value))) -} - -bindingExecutors.attr = function(val, elem, data) { - var method = data.type, - attrName = data.param - if (method === "css") { - avalon(elem).css(attrName, val) - } else if (method === "attr") { - - // ms-attr-class="xxx" vm.xxx="aaa bbb ccc"将元素的className设置为aaa bbb ccc - // ms-attr-class="xxx" vm.xxx=false 清空元素的所有类å - // ms-attr-name="yyy" vm.yyy="ooo" 为元素设置name属性 - var toRemove = (val === false) || (val === null) || (val === void 0) - - if (!W3C && propMap[attrName]) { //æ—§å¼IE下需è¦è¿›è¡Œå字映射 - attrName = propMap[attrName] - } - var bool = boolMap[attrName] - if (typeof elem[bool] === "boolean") { - elem[bool] = !! val //布尔属性必须使用el.xxx = true|falseæ–¹å¼è®¾å€¼ - if (!val) { //如果为false, IE全系列下相当于setAttribute(xxx,''),会影å“到样å¼,需è¦è¿›ä¸€æ­¥å¤„ç† - toRemove = true - } - } - if (toRemove) { - return elem.removeAttribute(attrName) - } - //SVGåªèƒ½ä½¿ç”¨setAttribute(xxx, yyy), VMLåªèƒ½ä½¿ç”¨elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy - var isInnate = rsvg.test(elem) ? false : (DOC.namespaces && isVML(elem)) ? true : attrName in elem.cloneNode(false) - if (isInnate) { - elem[attrName] = val+"" - } else { - elem.setAttribute(attrName, val) - } - } else if (method === "include" && val) { - var vmodels = data.vmodels - var rendered = data.includeRendered - var loaded = data.includeLoaded - var replace = data.includeReplace - var target = replace ? elem.parentNode : elem - var scanTemplate = function(text) { - if (loaded) { - var newText = loaded.apply(target, [text].concat(vmodels)) - if (typeof newText === "string") - text = newText - } - if (rendered) { - checkScan(target, function() { - rendered.call(target) - }, NaN) - } - var lastID = data.includeLastID - if (data.templateCache && lastID && lastID !== val) { - var lastTemplate = data.templateCache[lastID] - if (!lastTemplate) { - lastTemplate = data.templateCache[lastID] = DOC.createElement("div") - ifGroup.appendChild(lastTemplate) - } - } - data.includeLastID = val - while (true) { - var node = data.startInclude.nextSibling - if (node && node !== data.endInclude) { - target.removeChild(node) - if (lastTemplate) - lastTemplate.appendChild(node) - } else { - break - } - } - var dom = getTemplateNodes(data, val, text) - var nodes = avalon.slice(dom.childNodes) - target.insertBefore(dom, data.endInclude) - scanNodeArray(nodes, vmodels) - } - - if (data.param === "src") { - if (typeof templatePool[val] === "string") { - avalon.nextTick(function() { - scanTemplate(templatePool[val]) - }) - } else if (Array.isArray(templatePool[val])) { //#805 防止在循环绑定中å‘出许多相åŒçš„请求 - templatePool[val].push(scanTemplate) - } else { - var xhr = getXHR() - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - var s = xhr.status - if (s >= 200 && s < 300 || s === 304 || s === 1223) { - var text = xhr.responseText - for (var f = 0, fn; fn = templatePool[val][f++];) { - fn(text) - } - templatePool[val] = text - } - } - } - templatePool[val] = [scanTemplate] - xhr.open("GET", val, true) - if ("withCredentials" in xhr) { - xhr.withCredentials = true - } - xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") - xhr.send(null) - } - } else { - //IE系列与够新的标准æµè§ˆå™¨æ”¯æŒé€šè¿‡IDå–得元素(firefox14+) - //http://tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ - var el = val && val.nodeType === 1 ? val : DOC.getElementById(val) - if (el) { - if (el.tagName === "NOSCRIPT" && !(el.innerHTML || el.fixIE78)) { //IE7-8 innerText,innerHTML都无法å–得其内容,IE6能å–å¾—å…¶innerHTML - xhr = getXHR() //IE9-11与chromeçš„innerHTML会得到转义的内容,它们的innerTextå¯ä»¥ - xhr.open("GET", location, false) //谢谢Nodejs 乱炖群 深圳-纯属虚构 - xhr.send(null) - //http://bbs.csdn.net/topics/390349046?page=1#post-393492653 - var noscripts = DOC.getElementsByTagName("noscript") - var array = (xhr.responseText || "").match(rnoscripts) || [] - var n = array.length - for (var i = 0; i < n; i++) { - var tag = noscripts[i] - if (tag) { //IE6-8中noscript标签的innerHTML,innerText是åªè¯»çš„ - tag.style.display = "none" //http://haslayout.net/css/noscript-Ghost-Bug - tag.fixIE78 = (array[i].match(rnoscriptText) || ["", " "])[1] - } - } - } - avalon.nextTick(function() { - scanTemplate(el.fixIE78 || el.value || el.innerText || el.innerHTML) - }) - } - } - } else { - if (!root.hasAttribute && typeof val === "string" && (method === "src" || method === "href")) { - val = val.replace(/&/g, "&") //处ç†IE67自动转义的问题 - } - elem[method] = val - if (window.chrome && elem.tagName === "EMBED") { - var parent = elem.parentNode //#525 chrome1-37下embed标签动æ€è®¾ç½®srcä¸èƒ½å‘生请求 - var comment = document.createComment("ms-src") - parent.replaceChild(comment, elem) - parent.replaceChild(elem, comment) - } - } -} - -function getTemplateNodes(data, id, text) { - var div = data.templateCache && data.templateCache[id] - if (div) { - var dom = DOC.createDocumentFragment(), - firstChild - while (firstChild = div.firstChild) { - dom.appendChild(firstChild) - } - return dom - } - return avalon.parseHTML(text) -} - -//这几个指令都å¯ä»¥ä½¿ç”¨æ’值表达å¼ï¼Œå¦‚ms-src="aaa/{{b}}/{{c}}.html" -"title,alt,src,value,css,include,href".replace(rword, function(name) { - bindingHandlers[name] = bindingHandlers.attr -}) -//æ ¹æ®VM的属性值或表达å¼çš„值切æ¢ç±»å,ms-class="xxx yyy zzz:flag" -//http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html -bindingHandlers["class"] = function(data, vmodels) { - var oldStyle = data.param, - text = data.value, - rightExpr - data.handlerName = "class" - if (!oldStyle || isFinite(oldStyle)) { - data.param = "" //去掉数字 - var noExpr = text.replace(rexprg, function(a) { - return a.replace(/./g, "0") - //return Math.pow(10, a.length - 1) //å°†æ’值表达å¼æ’å…¥10çš„N-1次方æ¥å ä½ - }) - var colonIndex = noExpr.indexOf(":") //å–得第一个冒å·çš„ä½ç½® - if (colonIndex === -1) { // 比如 ms-class="aaa bbb ccc" 的情况 - var className = text - } else { // 比如 ms-class-1="ui-state-active:checked" 的情况 - className = text.slice(0, colonIndex) - rightExpr = text.slice(colonIndex + 1) - parseExpr(rightExpr, vmodels, data) //决定是添加还是删除 - if (!data.evaluator) { - log("debug: ms-class '" + (rightExpr || "").trim() + "' ä¸å­˜åœ¨äºŽVM中") - return false - } else { - data._evaluator = data.evaluator - data._args = data.args - } - } - var hasExpr = rexpr.test(className) //比如ms-class="width{{w}}"的情况 - if (!hasExpr) { - data.immobileClass = className - } - parseExprProxy("", vmodels, data, (hasExpr ? scanExpr(className) : 0)) - } else { - data.immobileClass = data.oldStyle = data.param - parseExprProxy(text, vmodels, data) - } -} - -bindingExecutors["class"] = function(val, elem, data) { - var $elem = avalon(elem), - method = data.type - if (method === "class" && data.oldStyle) { //如果是旧风格 - $elem.toggleClass(data.oldStyle, !! val) - } else { - //如果存在冒å·å°±æœ‰æ±‚值函数 - data.toggleClass = data._evaluator ? !! data._evaluator.apply(elem, data._args) : true - data.newClass = data.immobileClass || val - if (data.oldClass && data.newClass !== data.oldClass) { - $elem.removeClass(data.oldClass) - } - data.oldClass = data.newClass - switch (method) { - case "class": - $elem.toggleClass(data.newClass, data.toggleClass) - break - case "hover": - case "active": - if (!data.hasBindEvent) { //ç¡®ä¿åªç»‘定一次 - var activate = "mouseenter" //在移出移入时切æ¢ç±»å - var abandon = "mouseleave" - if (method === "active") { //在èšç„¦å¤±ç„¦ä¸­åˆ‡æ¢ç±»å - elem.tabIndex = elem.tabIndex || -1 - activate = "mousedown" - abandon = "mouseup" - var fn0 = $elem.bind("mouseleave", function() { - data.toggleClass && $elem.removeClass(data.newClass) - }) - } - var fn1 = $elem.bind(activate, function() { - data.toggleClass && $elem.addClass(data.newClass) - }) - var fn2 = $elem.bind(abandon, function() { - data.toggleClass && $elem.removeClass(data.newClass) - }) - data.rollback = function() { - $elem.unbind("mouseleave", fn0) - $elem.unbind(activate, fn1) - $elem.unbind(abandon, fn2) - } - data.hasBindEvent = true - } - break; - } - } -} - -"hover,active".replace(rword, function(method) { - bindingHandlers[method] = bindingHandlers["class"] -}) -//ms-controller绑定已ç»åœ¨scanTag 方法中实现 -//ms-css绑定已由ms-attr绑定实现 - - -// bindingHandlers.data 定义在if.js -bindingExecutors.data = function(val, elem, data) { - var key = "data-" + data.param - if (val && typeof val === "object") { - elem[key] = val - } else { - elem.setAttribute(key, String(val)) - } -} -//åŒå·¥ç»‘定 -var duplexBinding = bindingHandlers.duplex = function(data, vmodels) { - var elem = data.element, - hasCast - parseExprProxy(data.value, vmodels, data, 0, 1) - - data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop - if (data.evaluator && data.args) { - var params = [] - var casting = oneObject("string,number,boolean,checked") - if (elem.type === "radio" && data.param === "") { - data.param = "checked" - } - if (elem.msData) { - elem.msData["ms-duplex"] = data.value - } - data.param.replace(/\w+/g, function(name) { - if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) { - if (name === "radio") - log("ms-duplex-radioå·²ç»æ›´å为ms-duplex-checked") - name = "checked" - data.isChecked = true - } - if (name === "bool") { - name = "boolean" - log("ms-duplex-boolå·²ç»æ›´å为ms-duplex-boolean") - } else if (name === "text") { - name = "string" - log("ms-duplex-textå·²ç»æ›´å为ms-duplex-string") - } - if (casting[name]) { - hasCast = true - } - avalon.Array.ensure(params, name) - }) - if (!hasCast) { - params.push("string") - } - data.param = params.join("-") - data.bound = function(type, callback) { - if (elem.addEventListener) { - elem.addEventListener(type, callback, false) - } else { - elem.attachEvent("on" + type, callback) - } - var old = data.rollback - data.rollback = function() { - elem.avalonSetter = null - avalon.unbind(elem, type, callback) - old && old() - } - } - for (var i in avalon.vmodels) { - var v = avalon.vmodels[i] - v.$fire("avalon-ms-duplex-init", data) - } - var cpipe = data.pipe || (data.pipe = pipe) - cpipe(null, data, "init") - var tagName = elem.tagName - duplexBinding[tagName] && duplexBinding[tagName](elem, data.evaluator.apply(null, data.args), data) - } -} -//ä¸å­˜åœ¨ bindingExecutors.duplex - - function fixNull(val) { - return val == null ? "" : val - } -avalon.duplexHooks = { - checked: { - get: function(val, data) { - return !data.element.oldValue - } - }, - string: { - get: function(val) { //åŒæ­¥åˆ°VM - return val - }, - set: fixNull - }, - "boolean": { - get: function(val) { - return val === "true" - }, - set: fixNull - }, - number: { - get: function(val, data) { - var number = parseFloat(val) - if (-val === -number) { - return number - } - var arr = /strong|medium|weak/.exec(data.element.getAttribute("data-duplex-number")) || ["medium"] - switch (arr[0]) { - case "strong": - return 0 - case "medium": - return val === "" ? "" : 0 - case "weak": - return val - } - }, - set: fixNull - } -} - -function pipe(val, data, action, e) { - data.param.replace(/\w+/g, function(name) { - var hook = avalon.duplexHooks[name] - if (hook && typeof hook[action] === "function") { - val = hook[action](val, data) - } - }) - return val -} - -var TimerID, ribbon = [] - - avalon.tick = function(fn) { - if (ribbon.push(fn) === 1) { - TimerID = setInterval(ticker, 60) - } - } - - function ticker() { - for (var n = ribbon.length - 1; n >= 0; n--) { - var el = ribbon[n] - if (el() === false) { - ribbon.splice(n, 1) - } - } - if (!ribbon.length) { - clearInterval(TimerID) - } - } - -var watchValueInTimer = noop -var rmsinput = /text|password|hidden/ -new function() { // jshint ignore:line - try { //#272 IE9-IE11, firefox - var setters = {} - var aproto = HTMLInputElement.prototype - var bproto = HTMLTextAreaElement.prototype - function newSetter(value) { // jshint ignore:line - setters[this.tagName].call(this, value) - if (rmsinput.test(this.type) && !this.msFocus && this.avalonSetter) { - this.avalonSetter() - } - } - var inputProto = HTMLInputElement.prototype - Object.getOwnPropertyNames(inputProto) //æ•…æ„引å‘IE6-8ç­‰æµè§ˆå™¨æŠ¥é”™ - setters["INPUT"] = Object.getOwnPropertyDescriptor(aproto, "value").set - - Object.defineProperty(aproto, "value", { - set: newSetter - }) - setters["TEXTAREA"] = Object.getOwnPropertyDescriptor(bproto, "value").set - Object.defineProperty(bproto, "value", { - set: newSetter - }) - } catch (e) { - //在chrome 43中 ms-duplex终于ä¸éœ€è¦ä½¿ç”¨å®šæ—¶å™¨å®žçŽ°åŒå‘绑定了 - // http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype - // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1 - watchValueInTimer = avalon.tick - } -} // jshint ignore:line -if (IEVersion) { - avalon.bind(DOC, "selectionchange", function(e) { - var el = DOC.activeElement - if (el && typeof el.avalonSetter === "function") { - el.avalonSetter() - } - }) -} - -//处ç†radio, checkbox, text, textarea, password -duplexBinding.INPUT = function(element, evaluator, data) { - var $type = element.type, - bound = data.bound, - $elem = avalon(element), - composing = false - - function callback(value) { - data.changed.call(this, value, data) - } - - function compositionStart() { - composing = true - } - - function compositionEnd() { - composing = false - } - //当valueå˜åŒ–时改å˜model的值 - var updateVModel = function() { - if (composing) //处ç†ä¸­æ–‡è¾“入法在minlengh下引å‘çš„BUG - return - var val = element.oldValue = element.value //防止递归调用形æˆæ­»å¾ªçŽ¯ - var lastValue = data.pipe(val, data, "get") - if ($elem.data("duplexObserve") !== false) { - evaluator(lastValue) - callback.call(element, lastValue) - if ($elem.data("duplex-focus")) { - avalon.nextTick(function() { - element.focus() - }) - } - } - } - //当modelå˜åŒ–æ—¶,它就会改å˜value的值 - data.handler = function() { - var val = data.pipe(evaluator(), data, "set") + "" //fix #673 - if (val !== element.oldValue) { - element.value = val - } - } - if (data.isChecked || $type === "radio") { - var IE6 = IEVersion === 6 - updateVModel = function() { - if ($elem.data("duplexObserve") !== false) { - var lastValue = data.pipe(element.value, data, "get") - evaluator(lastValue) - callback.call(element, lastValue) - } - } - data.handler = function() { - var val = evaluator() - var checked = data.isChecked ? !! val : val + "" === element.value - element.oldValue = checked - if (IE6) { - setTimeout(function() { - //IE8 checkbox, radio是使用defaultChecked控制选中状æ€ï¼Œ - //并且è¦å…ˆè®¾ç½®defaultCheckedåŽè®¾ç½®checked - //并且必须设置延迟 - element.defaultChecked = checked - element.checked = checked - }, 31) - } else { - element.checked = checked - } - } - bound("click", updateVModel) - } else if ($type === "checkbox") { - updateVModel = function() { - if ($elem.data("duplexObserve") !== false) { - var method = element.checked ? "ensure" : "remove" - var array = evaluator() - if (!Array.isArray(array)) { - log("ms-duplex应用于checkbox上è¦å¯¹åº”一个数组") - array = [array] - } - var val = data.pipe(element.value, data, "get") - avalon.Array[method](array, val) - callback.call(element, array) - } - } - - data.handler = function() { - var array = [].concat(evaluator()) //强制转æ¢ä¸ºæ•°ç»„ - var val = data.pipe(element.value, data, "get") - element.checked = array.indexOf(val) > -1 - } - bound(W3C ? "change" : "click", updateVModel) - } else { - var events = element.getAttribute("data-duplex-event") || "input" - if (element.attributes["data-event"]) { - log("data-event指令已ç»åºŸå¼ƒï¼Œè¯·æ”¹ç”¨data-duplex-event") - } - - function delay(e) { // jshint ignore:line - setTimeout(function() { - updateVModel(e) - }) - } - events.replace(rword, function(name) { - switch (name) { - case "input": - if (!IEVersion) { // W3C - bound("input", updateVModel) - //éžIEæµè§ˆå™¨æ‰ç”¨è¿™ä¸ª - bound("compositionstart", compositionStart) - bound("compositionend", compositionEnd) - bound("DOMAutoComplete", updateVModel) - } else { //onpropertychange事件无法区分是程åºè§¦å‘è¿˜æ˜¯ç”¨æˆ·è§¦å‘ - // IE下通过selectionchange事件监å¬IE9+点击inputå³è¾¹çš„X的清空行为,åŠç²˜è´´ï¼Œå‰ªåˆ‡ï¼Œåˆ é™¤è¡Œä¸º - if (IEVersion > 8) { - bound("input", updateVModel) //IE9使用propertychange无法监å¬ä¸­æ–‡è¾“入改动 - } else { - bound("propertychange", function(e) { //IE6-8下第一次修改时ä¸ä¼šè§¦å‘,需è¦ä½¿ç”¨keydown或selectionchange修正 - if (e.propertyName === "value") { - updateVModel() - } - }) - } - bound("dragend", delay) - //http://www.cnblogs.com/rubylouvre/archive/2013/02/17/2914604.html - //http://www.matts411.com/post/internet-explorer-9-oninput/ - } - break - default: - bound(name, updateVModel) - break - } - }) - bound("focus", function() { - element.msFocus = true - }) - bound("blur", function() { - element.msFocus = false - }) - - if (rmsinput.test($type)) { - watchValueInTimer(function() { - if (root.contains(element)) { - if (!element.msFocus && element.oldValue !== element.value) { - updateVModel() - } - } else if (!element.msRetain) { - return false - } - }) - } - - element.avalonSetter = updateVModel //#765 - } - - element.oldValue = element.value - avalon.injectBinding(data) - callback.call(element, element.value) -} -duplexBinding.TEXTAREA = duplexBinding.INPUT -duplexBinding.SELECT = function(element, evaluator, data) { - var $elem = avalon(element) - - function updateVModel() { - if ($elem.data("duplexObserve") !== false) { - var val = $elem.val() //字符串或字符串数组 - if (Array.isArray(val)) { - val = val.map(function(v) { - return data.pipe(v, data, "get") - }) - } else { - val = data.pipe(val, data, "get") - } - if (val + "" !== element.oldValue) { - evaluator(val) - } - data.changed.call(element, val, data) - } - } - data.handler = function() { - var val = evaluator() - val = val && val.$model || val - if (Array.isArray(val)) { - if (!element.multiple) { - log("ms-duplex在ä¸èƒ½å¯¹åº”一个数组") - } - } - //å¿…é¡»å˜æˆå­—符串åŽæ‰èƒ½æ¯”较 - val = Array.isArray(val) ? val.map(String) : val + "" - if (val + "" !== element.oldValue) { - $elem.val(val) - element.oldValue = val + "" - } - } - data.bound("change", updateVModel) - element.msCallback = function() { - avalon.injectBinding(data) - data.changed.call(element, evaluator(), data) - } -} -// bindingHandlers.html 定义在if.js -bindingExecutors.html = function (val, elem, data) { - var isHtmlFilter = elem.nodeType !== 1 - var parent = isHtmlFilter ? elem.parentNode : elem - if (!parent) - return - val = val == null ? "" : val - if (data.oldText !== val) { - data.oldText = val - } else { - return - } - if (elem.nodeType === 3) { - var signature = generateID("html") - parent.insertBefore(DOC.createComment(signature), elem) - data.element = DOC.createComment(signature + ":end") - parent.replaceChild(data.element, elem) - elem = data.element - } - if (typeof val !== "object") {//string, number, boolean - var fragment = avalon.parseHTML(String(val)) - } else if (val.nodeType === 11) { //å°†val转æ¢ä¸ºæ–‡æ¡£ç¢Žç‰‡ - fragment = val - } else if (val.nodeType === 1 || val.item) { - var nodes = val.nodeType === 1 ? val.childNodes : val.item - fragment = avalonFragment.cloneNode(true) - while (nodes[0]) { - fragment.appendChild(nodes[0]) - } - } - - nodes = avalon.slice(fragment.childNodes) - //æ’å…¥å ä½ç¬¦, 如果是过滤器,需è¦æœ‰èŠ‚制地移除指定的数é‡,如果是html指令,直接清空 - if (isHtmlFilter) { - var endValue = elem.nodeValue.slice(0, -4) - while (true) { - var node = elem.previousSibling - if (!node || node.nodeType === 8 && node.nodeValue === endValue) { - break - } else { - parent.removeChild(node) - } - } - parent.insertBefore(fragment, elem) - } else { - avalon.clearHTML(elem).appendChild(fragment) - } - scanNodeArray(nodes, data.vmodels) -} -bindingHandlers["if"] = - bindingHandlers.data = - bindingHandlers.text = - bindingHandlers.html = - function(data, vmodels) { - parseExprProxy(data.value, vmodels, data) -} - -bindingExecutors["if"] = function(val, elem, data) { - try { - if(!elem.parentNode) return - } catch(e) {return} - if (val) { //æ’回DOMæ ‘ - if (elem.nodeType === 8) { - elem.parentNode.replaceChild(data.template, elem) - // animate.enter(data.template, elem.parentNode) - elem = data.element = data.template //这时å¯èƒ½ä¸ºnull - } - if (elem.getAttribute(data.name)) { - elem.removeAttribute(data.name) - scanAttr(elem, data.vmodels) - } - data.rollback = null - } else { //移出DOM树,并用注释节点å æ®åŽŸä½ç½® - if (elem.nodeType === 1) { - var node = data.element = DOC.createComment("ms-if") - elem.parentNode.replaceChild(node, elem) - // animate.leave(elem, node.parentNode, node) - data.template = elem //元素节点 - ifGroup.appendChild(elem) - data.rollback = function() { - if (elem.parentNode === ifGroup) { - ifGroup.removeChild(elem) - } - } - } - } -} -//ms-important绑定已ç»åœ¨scanTag 方法中实现 -//ms-include绑定已由ms-attr绑定实现 - -var rdash = /\(([^)]*)\)/ -bindingHandlers.on = function(data, vmodels) { - var value = data.value - data.type = "on" - var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10 - if (typeof bindingHandlers.on[eventType + "Hook"] === "function") { - bindingHandlers.on[eventType + "Hook"](data) - } - if (value.indexOf("(") > 0 && value.indexOf(")") > -1) { - var matched = (value.match(rdash) || ["", ""])[1].trim() - if (matched === "" || matched === "$event") { // aaa() aaa($event)当æˆaaaå¤„ç† - value = value.replace(rdash, "") - } - } - parseExprProxy(value, vmodels, data) -} - -bindingExecutors.on = function(callback, elem, data) { - callback = function(e) { - var fn = data.evaluator || noop - return fn.apply(this, data.args.concat(e)) - } - var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10 - if (eventType === "scan") { - callback.call(elem, { - type: eventType - }) - } else if (typeof data.specialBind === "function") { - data.specialBind(elem, callback) - } else { - var removeFn = avalon.bind(elem, eventType, callback) - } - data.rollback = function() { - if (typeof data.specialUnbind === "function") { - data.specialUnbind() - } else { - avalon.unbind(elem, eventType, removeFn) - } - } -} -bindingHandlers.repeat = function (data, vmodels) { - var type = data.type - parseExprProxy(data.value, vmodels, data, 0, 1) - data.proxies = [] - var freturn = false - try { - var $repeat = data.$repeat = data.evaluator.apply(0, data.args || []) - var xtype = avalon.type($repeat) - if (xtype !== "object" && xtype !== "array") { - freturn = true - avalon.log("warning:" + data.value + "åªèƒ½æ˜¯å¯¹è±¡æˆ–数组") - } - } catch (e) { - freturn = true - } - var arr = data.value.split(".") || [] - if (arr.length > 1) { - arr.pop() - var n = arr[0] - for (var i = 0, v; v = vmodels[i++]; ) { - if (v && v.hasOwnProperty(n)) { - var events = v[n].$events || {} - events[subscribers] = events[subscribers] || [] - events[subscribers].push(data) - break - } - } - } - - var elem = data.element - if (elem.nodeType === 1) { - elem.removeAttribute(data.name) - data.sortedCallback = getBindingCallback(elem, "data-with-sorted", vmodels) - data.renderedCallback = getBindingCallback(elem, "data-" + type + "-rendered", vmodels) - var signature = generateID(type) - var start = DOC.createComment(signature) - var end = DOC.createComment(signature + ":end") - data.signature = signature - data.template = avalonFragment.cloneNode(false) - if (type === "repeat") { - var parent = elem.parentNode - parent.replaceChild(end, elem) - parent.insertBefore(start, end) - data.template.appendChild(elem) - } else { - while (elem.firstChild) { - data.template.appendChild(elem.firstChild) - } - elem.appendChild(start) - elem.appendChild(end) - } - data.element = end - data.handler = bindingExecutors.repeat - data.rollback = function () { - var elem = data.element - if (!elem) - return - data.handler("clear") - } - } - - if (freturn) { - return - } - - data.$outer = {} - var check0 = "$key" - var check1 = "$val" - if (Array.isArray($repeat)) { - check0 = "$first" - check1 = "$last" - } - - for (i = 0; v = vmodels[i++]; ) { - if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) { - data.$outer = v - break - } - } - var $events = $repeat.$events - var $list = ($events || {})[subscribers] - injectDependency($list, data) - if (xtype === "object") { - data.$with = true - $repeat.$proxy || ($repeat.$proxy = {}) - data.handler("append", $repeat) - } else if ($repeat.length) { - data.handler("add", 0, $repeat.length) - } -} - -bindingExecutors.repeat = function (method, pos, el) { - if (!method && this.$with) { - method = "append" - var flag = "update" - } - if (method) { - var data = this, start, fragment - var end = data.element - var comments = getComments(data) - var parent = end.parentNode - var proxies = data.proxies - var transation = avalonFragment.cloneNode(false) - switch (method) { - case "add": //在posä½ç½®åŽæ·»åŠ el数组(pos为æ’å…¥ä½ç½®,el为è¦æ’入的个数) - var n = pos + el - var fragments = [] - for (var i = pos; i < n; i++) { - var proxy = eachProxyAgent(i, data) - proxies.splice(i, 0, proxy) - shimController(data, transation, proxy, fragments) - } - var now = new Date() - 0 - avalon.optimize = avalon.optimize || now - for (i = 0; fragment = fragments[i++]; ) { - scanNodeArray(fragment.nodes, fragment.vmodels) - fragment.nodes = fragment.vmodels = null - } - if (avalon.optimize === now) { - avalon.optimize = null - } - parent.insertBefore(transation, comments[pos] || end) - avalon.profile("æ’å…¥æ“作花费了 " + (new Date - now)) - break - case "del": //å°†posåŽçš„el个元素删掉(pos, el都是数字) - sweepNodes(comments[pos], comments[pos + el] || end) - var removed = proxies.splice(pos, el) - recycleProxies(removed, "each") - break - case "clear": - start = comments[0] - if (start) { - sweepNodes(start, end) - if (data.$with) { - parent.insertBefore(start, end) - } - } - recycleProxies(proxies, "each") - break - case "move": - start = comments[0] - if (start) { - var signature = start.nodeValue - var rooms = [] - var room = [], - node - sweepNodes(start, end, function () { - room.unshift(this) - if (this.nodeValue === signature) { - rooms.unshift(room) - room = [] - } - }) - sortByIndex(rooms, pos) - sortByIndex(proxies, pos) - while (room = rooms.shift()) { - while (node = room.shift()) { - transation.appendChild(node) - } - } - parent.insertBefore(transation, end) - } - break - case "index": //å°†proxies中的第pos个起的所有元素é‡æ–°ç´¢å¼• - var last = proxies.length - 1 - for (; el = proxies[pos]; pos++) { - el.$index = pos - el.$first = pos === 0 - el.$last = pos === last - } - return - case "set": //å°†proxies中的第pos个元素的VM设置为el(pos为数字,elä»»æ„) - proxy = proxies[pos] - if (proxy) { - fireDependencies(proxy.$events[data.param || "el"]) - } - break - case "append": - var object = data.$repeat //原æ¥ç¬¬2å‚数, 被循环对象 - var oldProxy = object.$proxy //代ç†å¯¹è±¡ç»„æˆçš„hash - var keys = [] - now = new Date() - 0 - avalon.optimize = avalon.optimize || now - if (flag === "update") { - if (!data.evaluator) { - parseExprProxy(data.value, data.vmodels, data, 0, 1) - } - object = data.$repeat = data.evaluator.apply(0, data.args || []) - object.$proxy = oldProxy - } - var pool = object.$proxy || {} - removed = [] - var nodes = data.element.parentNode.childNodes - var add = false - for (i = 0; node = nodes[i++]; ) { - if (node.nodeValue === data.signature) { - add = true - } else if (node.nodeValue === data.signature + ":end") { - add = false - } - if (add) { - removed.push(node) - } - } - - var indexNode = [], item - var keyIndex = data.keyIndex || (data.keyIndex = {}) - //将现有的节点全部移出DOMæ ‘ - for ( i = 0; i < removed.length; i++) { - el = removed[i] - if (el.nodeValue === data.signature) { - item = avalonFragment.cloneNode(false) - indexNode.push(item) - } - item.appendChild(el) - } - - - for (var key in object) { //当å‰å¯¹è±¡çš„所有键å - if (object.hasOwnProperty(key) && key !== "hasOwnProperty" && key !== "$proxy") { - keys.push(key) - } - } - - for (var i = 0; key = keys[i++]; ) { - if (!pool.hasOwnProperty(key)) {//添加缺失的代ç†VM - pool[key] = withProxyAgent(pool[key], key, data) - } else { - pool[key].$val = object[key] - } - } - - for ( key in pool) { - if (keys.indexOf(key) === -1) {//删除没用的代ç†VM - proxyRecycler(pool[key], withProxyPool) //去掉之å‰çš„代ç†VM - delete pool[key] - } - } - var fragments = [] - var renderKeys = keys //需è¦æ¸²æŸ“到DOM树去的键å - var end = data.element - if (data.sortedCallback) { //å¦‚æžœæœ‰å›žè°ƒï¼Œåˆ™è®©å®ƒä»¬æŽ’åº - var keys2 = data.sortedCallback.call(parent, keys) - if (keys2 && Array.isArray(keys2)) { - renderKeys = keys2 - } - } - - for (i = 0; i < renderKeys.length; i++) { - key = renderKeys[i] - if (typeof keyIndex[key] === "number") { - transation.appendChild(indexNode[keyIndex[key]]) - fragments.push({}) - } else { - shimController(data, transation, pool[key], fragments) - } - } - - for (i = 0; i < renderKeys.length; i++) { - keyIndex[renderKeys[i]] = i - } - - for (i = 0; fragment = fragments[i++]; ) { - if (fragment.nodes) { - scanNodeArray(fragment.nodes, fragment.vmodels) - fragment.nodes = fragment.vmodels = null - } - } - if (avalon.optimize === now) { - avalon.optimize = null - } - parent.insertBefore(transation, end) - avalon.profile("æ’å…¥æ“作花费了 " + (new Date - now)) - break - } - if (!data.$repeat || data.$repeat.hasOwnProperty("$lock")) //IE6-8 VBScript对象会报错, 有时候data.$repeatä¸å­˜åœ¨ - return - if (method === "clear") - method = "del" - var callback = data.renderedCallback || noop, - args = arguments - if (parent.oldValue && parent.tagName === "SELECT") { //fix #503 - avalon(parent).val(parent.oldValue.split(",")) - } - callback.apply(parent, args) - } -} -"with,each".replace(rword, function (name) { - bindingHandlers[name] = bindingHandlers.repeat -}) - -function shimController(data, transation, proxy, fragments) { - var content = data.template.cloneNode(true) - var nodes = avalon.slice(content.childNodes) - content.insertBefore(DOC.createComment(data.signature), content.firstChild) - transation.appendChild(content) - var nv = [proxy].concat(data.vmodels) - var fragment = { - nodes: nodes, - vmodels: nv - } - fragments.push(fragment) -} - -function getComments(data) { - var ret = [] - var nodes = data.element.parentNode.childNodes - for(var i= 0, node; node = nodes[i++];){ - if(node.nodeValue === data.signature){ - ret.push( node ) - }else if(node.nodeValue === data.signature+":end"){ - break - } - } - return ret -} - - -//移除掉start与end之间的节点(ä¿ç•™end) -function sweepNodes(start, end, callback) { - while (true) { - var node = end.previousSibling - if (!node) - break - node.parentNode.removeChild(node) - callback && callback.call(node) - if (node === start) { - break - } - } -} - -// 为ms-each,ms-with, ms-repeat会创建一个代ç†VM, -// 通过它们ä¿æŒä¸€ä¸ªä¸‹ä¸Šæ–‡ï¼Œè®©ç”¨æˆ·èƒ½è°ƒç”¨$index,$first,$last,$remove,$key,$val,$outer等属性与方法 -// 所有代ç†VM的产生,消费,收集,存放通过xxxProxyFactory,xxxProxyAgent, recycleProxies,xxxProxyPool实现 -var withProxyPool = [] -function withProxyFactory() { - var proxy = modelFactory({ - $key: "", - $outer: {}, - $host: {}, - $val: { - get: function () { - return this.$host[this.$key] - }, - set: function (val) { - this.$host[this.$key] = val - } - } - }, { - $val: 1 - }) - proxy.$id = generateID("$proxy$with") - return proxy -} - -function withProxyAgent(proxy, key, data) { - proxy = proxy || withProxyPool.pop() - if (!proxy) { - proxy = withProxyFactory() - } else { - proxy.$reinitialize() - } - var host = data.$repeat - proxy.$key = key - proxy.$host = host - proxy.$outer = data.$outer - if (host.$events) { - proxy.$events.$val = host.$events[key] - } else { - proxy.$events = {} - } - return proxy -} - - -function recycleProxies(proxies) { - eachProxyRecycler(proxies) -} -function eachProxyRecycler(proxies) { - proxies.forEach(function (proxy) { - proxyRecycler(proxy, eachProxyPool) - }) - proxies.length = 0 -} - - -var eachProxyPool = [] -function eachProxyFactory(name) { - var source = { - $host: [], - $outer: {}, - $index: 0, - $first: false, - $last: false, - $remove: avalon.noop - } - source[name] = { - get: function () { - var e = this.$events - var array = e.$index - e.$index = e[name] //#817 通过$index为el收集ä¾èµ– - try { - return this.$host[this.$index] - } finally { - e.$index = array - } - }, - set: function (val) { - try { - var e = this.$events - var array = e.$index - e.$index = [] - this.$host.set(this.$index, val) - } finally { - e.$index = array - } - } - } - var second = { - $last: 1, - $first: 1, - $index: 1 - } - var proxy = modelFactory(source, second) - proxy.$id = generateID("$proxy$each") - return proxy -} - -function eachProxyAgent(index, data) { - var param = data.param || "el", - proxy - for (var i = 0, n = eachProxyPool.length; i < n; i++) { - var candidate = eachProxyPool[i] - if (candidate && candidate.hasOwnProperty(param)) { - proxy = candidate - eachProxyPool.splice(i, 1) - } - } - if (!proxy) { - proxy = eachProxyFactory(param) - } - var host = data.$repeat - var last = host.length - 1 - proxy.$index = index - proxy.$first = index === 0 - proxy.$last = index === last - proxy.$host = host - proxy.$outer = data.$outer - proxy.$remove = function () { - return host.removeAt(proxy.$index) - } - return proxy -} - - -function proxyRecycler(proxy, proxyPool) { - for (var i in proxy.$events) { - if (Array.isArray(proxy.$events[i])) { - proxy.$events[i].forEach(function (data) { - if (typeof data === "object") - disposeData(data) - })// jshint ignore:line - proxy.$events[i].length = 0 - } - } - proxy.$host = proxy.$outer = {} - if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) { - proxyPool.pop() - } -} -/********************************************************************* - * å„ç§æŒ‡ä»¤ * - **********************************************************************/ -//ms-skip绑定已ç»åœ¨scanTag 方法中实现 -// bindingHandlers.text 定义在if.js -bindingExecutors.text = function(val, elem) { - val = val == null ? "" : val //ä¸åœ¨é¡µé¢ä¸Šæ˜¾ç¤ºundefined null - if (elem.nodeType === 3) { //绑定在文本节点上 - try { //IE对游离于DOM树外的节点赋值会报错 - elem.data = val - } catch (e) {} - } else { //绑定在特性节点上 - if ("textContent" in elem) { - elem.textContent = val - } else { - elem.innerText = val - } - } -} -function parseDisplay(nodeName, val) { - //用于å–得此类标签的默认display值 - var key = "_" + nodeName - if (!parseDisplay[key]) { - var node = DOC.createElement(nodeName) - root.appendChild(node) - if (W3C) { - val = getComputedStyle(node, null).display - } else { - val = node.currentStyle.display - } - root.removeChild(node) - parseDisplay[key] = val - } - return parseDisplay[key] -} - -avalon.parseDisplay = parseDisplay - -bindingHandlers.visible = function(data, vmodels) { - var elem = data.element - var display = elem.style.display - if(display === "none"){ - display = parseDisplay(elem.nodeName) - } - data.display = display - parseExprProxy(data.value, vmodels, data) -} - -bindingExecutors.visible = function(val, elem, data) { - elem.style.display = val ? data.display : "none" -} -bindingHandlers.widget = function(data, vmodels) { - var args = data.value.match(rword) - var elem = data.element - var widget = args[0] - var id = args[1] - if (!id || id === "$") { //没有定义或为$时,å–组件å+éšæœºæ•° - id = generateID(widget) - } - var optName = args[2] || widget //没有定义,å–组件å - var constructor = avalon.ui[widget] - if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname" - vmodels = elem.vmodels || vmodels - for (var i = 0, v; v = vmodels[i++];) { - if (v.hasOwnProperty(optName) && typeof v[optName] === "object") { - var vmOptions = v[optName] - vmOptions = vmOptions.$model || vmOptions - break - } - } - if (vmOptions) { - var wid = vmOptions[widget + "Id"] - if (typeof wid === "string") { - log("warning!ä¸å†æ”¯æŒ" + widget + "Id") - id = wid - } - } - //抽å–data-tooltip-textã€data-tooltip-attr属性,组æˆä¸€ä¸ªé…置对象 - var widgetData = avalon.getWidgetData(elem, widget) - data.value = [widget, id, optName].join(",") - data[widget + "Id"] = id - data.evaluator = noop - elem.msData["ms-widget-id"] = id - var options = data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData) - elem.removeAttribute("ms-widget") - var vmodel = constructor(elem, data, vmodels) || {} //防止组件ä¸è¿”回VM - if (vmodel.$id) { - avalon.vmodels[id] = vmodel - createSignalTower(elem, vmodel) - try { - vmodel.$init(function() { - avalon.scan(elem, [vmodel].concat(vmodels)) - if (typeof options.onInit === "function") { - options.onInit.call(elem, vmodel, options, vmodels) - } - }) - } catch (e) {} - data.rollback = function() { - try { - vmodel.widgetElement = null - vmodel.$remove() - } catch (e) {} - elem.msData = {} - delete avalon.vmodels[vmodel.$id] - } - injectDisposeQueue(data, widgetList) - if (window.chrome) { - elem.addEventListener("DOMNodeRemovedFromDocument", function() { - setTimeout(rejectDisposeQueue) - }) - } - } else { - avalon.scan(elem, vmodels) - } - } else if (vmodels.length) { //如果该组件还没有加载,那么ä¿å­˜å½“å‰çš„vmodels - elem.vmodels = vmodels - } -} -var widgetList = [] -//ä¸å­˜åœ¨ bindingExecutors.widget -/********************************************************************* - * 自带过滤器 * - **********************************************************************/ -var rscripts = /]*>([\S\s]*?)<\/script\s*>/gim -var ron = /\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g -var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig -var rsanitize = { - a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig, - img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig, - form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig -} -var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g -var rnoalphanumeric = /([^\#-~| |!])/g; - -function numberFormat(number, decimals, point, thousands) { - //form http://phpjs.org/functions/number_format/ - //number 必需,è¦æ ¼å¼åŒ–çš„æ•°å­— - //decimals å¯é€‰ï¼Œè§„定多少个å°æ•°ä½ã€‚ - //point å¯é€‰ï¼Œè§„定用作å°æ•°ç‚¹çš„字符串(默认为 . )。 - //thousands å¯é€‰ï¼Œè§„定用作åƒä½åˆ†éš”符的字符串(默认为 , ),如果设置了该å‚数,那么所有其他å‚数都是必需的。 - number = (number + '') - .replace(/[^0-9+\-Ee.]/g, '') - var n = !isFinite(+number) ? 0 : +number, - prec = !isFinite(+decimals) ? 3 : Math.abs(decimals), - sep = thousands || ",", - dec = point || ".", - s = '', - toFixedFix = function(n, prec) { - var k = Math.pow(10, prec) - return '' + (Math.round(n * k) / k) - .toFixed(prec) - } - // Fix for IE parseFloat(0.55).toFixed(0) = 0; - s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)) - .split('.') - if (s[0].length > 3) { - s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep) - } - if ((s[1] || '') - .length < prec) { - s[1] = s[1] || '' - s[1] += new Array(prec - s[1].length + 1) - .join('0') - } - return s.join(dec) -} - - -var filters = avalon.filters = { - uppercase: function(str) { - return str.toUpperCase() - }, - lowercase: function(str) { - return str.toLowerCase() - }, - truncate: function(str, length, truncation) { - //length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串 - length = length || 30 - truncation = typeof truncation === "string" ? truncation : "..." - return str.length > length ? str.slice(0, length - truncation.length) + truncation : String(str) - }, - $filter: function(val) { - for (var i = 1, n = arguments.length; i < n; i++) { - var array = arguments[i] - var fn = avalon.filters[array.shift()] - if (typeof fn === "function") { - var arr = [val].concat(array) - val = fn.apply(null, arr) - } - } - return val - }, - camelize: camelize, - //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet - // chrome - // chrome - // IE67chrome - // IE67chrome - // IE67chrome - sanitize: function(str) { - return str.replace(rscripts, "").replace(ropen, function(a, b) { - var match = a.toLowerCase().match(/<(\w+)\s/) - if (match) { //处ç†a标签的href属性,img标签的src属性,form标签的action属性 - var reg = rsanitize[match[1]] - if (reg) { - a = a.replace(reg, function(s, name, value) { - var quote = value.charAt(0) - return name + "=" + quote + "javascript:void(0)" + quote// jshint ignore:line - }) - } - } - return a.replace(ron, " ").replace(/\s+/g, " ") //移除onXXX事件 - }) - }, - escape: function(str) { - //将字符串ç»è¿‡ str 转义得到适åˆåœ¨é¡µé¢ä¸­æ˜¾ç¤ºçš„内容, ä¾‹å¦‚æ›¿æ¢ < 为 < - return String(str). - replace(/&/g, '&'). - replace(rsurrogate, function(value) { - var hi = value.charCodeAt(0) - var low = value.charCodeAt(1) - return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';' - }). - replace(rnoalphanumeric, function(value) { - return '&#' + value.charCodeAt(0) + ';' - }). - replace(//g, '>') - }, - currency: function(amount, symbol, fractionSize) { - return (symbol || "\uFFE5") + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2) - }, - number: numberFormat -} -/* - 'yyyy': 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010) - 'yy': 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) - 'y': 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199) - 'MMMM': Month in year (January-December) - 'MMM': Month in year (Jan-Dec) - 'MM': Month in year, padded (01-12) - 'M': Month in year (1-12) - 'dd': Day in month, padded (01-31) - 'd': Day in month (1-31) - 'EEEE': Day in Week,(Sunday-Saturday) - 'EEE': Day in Week, (Sun-Sat) - 'HH': Hour in day, padded (00-23) - 'H': Hour in day (0-23) - 'hh': Hour in am/pm, padded (01-12) - 'h': Hour in am/pm, (1-12) - 'mm': Minute in hour, padded (00-59) - 'm': Minute in hour (0-59) - 'ss': Second in minute, padded (00-59) - 's': Second in minute (0-59) - 'a': am/pm marker - 'Z': 4 digit (+sign) representation of the timezone offset (-1200-+1200) - format string can also be one of the following predefined localizable formats: - - 'medium': equivalent to 'MMM d, y h:mm:ss a' for en_US locale (e.g. Sep 3, 2010 12:05:08 pm) - 'short': equivalent to 'M/d/yy h:mm a' for en_US locale (e.g. 9/3/10 12:05 pm) - 'fullDate': equivalent to 'EEEE, MMMM d,y' for en_US locale (e.g. Friday, September 3, 2010) - 'longDate': equivalent to 'MMMM d, y' for en_US locale (e.g. September 3, 2010 - 'mediumDate': equivalent to 'MMM d, y' for en_US locale (e.g. Sep 3, 2010) - 'shortDate': equivalent to 'M/d/yy' for en_US locale (e.g. 9/3/10) - 'mediumTime': equivalent to 'h:mm:ss a' for en_US locale (e.g. 12:05:08 pm) - 'shortTime': equivalent to 'h:mm a' for en_US locale (e.g. 12:05 pm) - */ -new function() {// jshint ignore:line - function toInt(str) { - return parseInt(str, 10) || 0 - } - - function padNumber(num, digits, trim) { - var neg = "" - if (num < 0) { - neg = '-' - num = -num - } - num = "" + num - while (num.length < digits) - num = "0" + num - if (trim) - num = num.substr(num.length - digits) - return neg + num - } - - function dateGetter(name, size, offset, trim) { - return function(date) { - var value = date["get" + name]() - if (offset > 0 || value > -offset) - value += offset - if (value === 0 && offset === -12) { - value = 12 - } - return padNumber(value, size, trim) - } - } - - function dateStrGetter(name, shortForm) { - return function(date, formats) { - var value = date["get" + name]() - var get = (shortForm ? ("SHORT" + name) : name).toUpperCase() - return formats[get][value] - } - } - - function timeZoneGetter(date) { - var zone = -1 * date.getTimezoneOffset() - var paddedZone = (zone >= 0) ? "+" : "" - paddedZone += padNumber(Math[zone > 0 ? "floor" : "ceil"](zone / 60), 2) + padNumber(Math.abs(zone % 60), 2) - return paddedZone - } - //å–得上åˆä¸‹åˆ - - function ampmGetter(date, formats) { - return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1] - } - var DATE_FORMATS = { - yyyy: dateGetter("FullYear", 4), - yy: dateGetter("FullYear", 2, 0, true), - y: dateGetter("FullYear", 1), - MMMM: dateStrGetter("Month"), - MMM: dateStrGetter("Month", true), - MM: dateGetter("Month", 2, 1), - M: dateGetter("Month", 1, 1), - dd: dateGetter("Date", 2), - d: dateGetter("Date", 1), - HH: dateGetter("Hours", 2), - H: dateGetter("Hours", 1), - hh: dateGetter("Hours", 2, -12), - h: dateGetter("Hours", 1, -12), - mm: dateGetter("Minutes", 2), - m: dateGetter("Minutes", 1), - ss: dateGetter("Seconds", 2), - s: dateGetter("Seconds", 1), - sss: dateGetter("Milliseconds", 3), - EEEE: dateStrGetter("Day"), - EEE: dateStrGetter("Day", true), - a: ampmGetter, - Z: timeZoneGetter - } - var rdateFormat = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/ - var raspnetjson = /^\/Date\((\d+)\)\/$/ - filters.date = function(date, format) { - var locate = filters.date.locate, - text = "", - parts = [], - fn, match - format = format || "mediumDate" - format = locate[format] || format - if (typeof date === "string") { - if (/^\d+$/.test(date)) { - date = toInt(date) - } else if (raspnetjson.test(date)) { - date = +RegExp.$1 - } else { - var trimDate = date.trim() - var dateArray = [0, 0, 0, 0, 0, 0, 0] - var oDate = new Date(0) - //å–得年月日 - trimDate = trimDate.replace(/^(\d+)\D(\d+)\D(\d+)/, function(_, a, b, c) { - var array = c.length === 4 ? [c, a, b] : [a, b, c] - dateArray[0] = toInt(array[0]) //å¹´ - dateArray[1] = toInt(array[1]) - 1 //月 - dateArray[2] = toInt(array[2]) //æ—¥ - return "" - }) - var dateSetter = oDate.setFullYear - var timeSetter = oDate.setHours - trimDate = trimDate.replace(/[T\s](\d+):(\d+):?(\d+)?\.?(\d)?/, function(_, a, b, c, d) { - dateArray[3] = toInt(a) //å°æ—¶ - dateArray[4] = toInt(b) //分钟 - dateArray[5] = toInt(c) //秒 - if (d) { //毫秒 - dateArray[6] = Math.round(parseFloat("0." + d) * 1000) - } - return "" - }) - var tzHour = 0 - var tzMin = 0 - trimDate = trimDate.replace(/Z|([+-])(\d\d):?(\d\d)/, function(z, symbol, c, d) { - dateSetter = oDate.setUTCFullYear - timeSetter = oDate.setUTCHours - if (symbol) { - tzHour = toInt(symbol + c) - tzMin = toInt(symbol + d) - } - return "" - }) - - dateArray[3] -= tzHour - dateArray[4] -= tzMin - dateSetter.apply(oDate, dateArray.slice(0, 3)) - timeSetter.apply(oDate, dateArray.slice(3)) - date = oDate - } - } - if (typeof date === "number") { - date = new Date(date) - } - if (avalon.type(date) !== "date") { - return - } - while (format) { - match = rdateFormat.exec(format) - if (match) { - parts = parts.concat(match.slice(1)) - format = parts.pop() - } else { - parts.push(format) - format = null - } - } - parts.forEach(function(value) { - fn = DATE_FORMATS[value] - text += fn ? fn(date, locate) : value.replace(/(^'|'$)/g, "").replace(/''/g, "'") - }) - return text - } - var locate = { - AMPMS: { - 0: "上åˆ", - 1: "下åˆ" - }, - DAY: { - 0: "星期日", - 1: "星期一", - 2: "星期二", - 3: "星期三", - 4: "星期四", - 5: "星期五", - 6: "星期六" - }, - MONTH: { - 0: "1月", - 1: "2月", - 2: "3月", - 3: "4月", - 4: "5月", - 5: "6月", - 6: "7月", - 7: "8月", - 8: "9月", - 9: "10月", - 10: "11月", - 11: "12月" - }, - SHORTDAY: { - "0": "周日", - "1": "周一", - "2": "周二", - "3": "周三", - "4": "周四", - "5": "周五", - "6": "周六" - }, - fullDate: "yå¹´M月dæ—¥EEEE", - longDate: "yå¹´M月dæ—¥", - medium: "yyyy-M-d H:mm:ss", - mediumDate: "yyyy-M-d", - mediumTime: "H:mm:ss", - "short": "yy-M-d ah:mm", - shortDate: "yy-M-d", - shortTime: "ah:mm" - } - locate.SHORTMONTH = locate.MONTH - filters.date.locate = locate -}// jshint ignore:line -/********************************************************************* - * AMD加载器 * - **********************************************************************/ -//https://www.devbridge.com/articles/understanding-amd-requirejs/ -//http://maxogden.com/nested-dependencies.html -var modules = avalon.modules = { - "domReady!": { - exports: avalon, - state: 3 - }, - "avalon": { - exports: avalon, - state: 4 - } -} -//Object(modules[id]).state拥有如下值 -// undefined 没有定义 -// 1(send) å·²ç»å‘出请求 -// 2(loading) å·²ç»è¢«æ‰§è¡Œä½†è¿˜æ²¡æœ‰æ‰§è¡Œå®Œæˆï¼Œåœ¨è¿™ä¸ªé˜¶æ®µdefine方法会被执行 -// 3(loaded) 执行完毕,通过onload/onreadystatechange回调判定,在这个阶段checkDeps方法会执行 -// 4(execute) å…¶ä¾èµ–也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行 -modules.exports = modules.avalon - -new function () {// jshint ignore:line - var loadings = [] //正在加载中的模å—列表 - var factorys = [] //放置define方法的factory函数 - var rjsext = /\.js$/i - function makeRequest(name, config) { -//1. 去掉资æºå‰ç¼€ - var res = "js" - name = name.replace(/^(\w+)\!/, function (a, b) { - res = b - return "" - }) - if (res === "ready") { - log("debug: ready!å·²ç»è¢«åºŸå¼ƒï¼Œè¯·ä½¿ç”¨domReady!") - res = "domReady" - } -//2. 去掉querystring, hash - var query = "" - name = name.replace(rquery, function (a) { - query = a - return "" - }) - //3. 去掉扩展å - var suffix = "." + res - var ext = /js|css/.test(suffix) ? suffix : "" - name = name.replace(/\.[a-z0-9]+$/g, function (a) { - if (a === suffix) { - ext = a - return "" - } else { - return a - } - }) - var req = avalon.mix({ - query: query, - ext: ext, - res: res, - name: name, - toUrl: toUrl - }, config) - req.toUrl(name) - return req - } - - function fireRequest(req) { - var name = req.name - var res = req.res - //1. 如果该模å—å·²ç»å‘出请求,直接返回 - var module = modules[name] - var urlNoQuery = name && req.urlNoQuery - if (module && module.state >= 1) { - return name - } - module = modules[urlNoQuery] - if (module && module.state >= 3) { - innerRequire(module.deps || [], module.factory, urlNoQuery) - return urlNoQuery - } - if (name && !module) { - module = modules[urlNoQuery] = { - id: urlNoQuery, - state: 1 //send - } - var wrap = function (obj) { - resources[res] = obj - obj.load(name, req, function (a) { - if (arguments.length && a !== void 0) { - module.exports = a - } - module.state = 4 - checkDeps() - }) - } - - if (!resources[res]) { - innerRequire([res], wrap) - } else { - wrap(resources[res]) - } - } - return name ? urlNoQuery : res + "!" - } - -//核心API之一 require - var requireQueue = [] - var isUserFirstRequire = false - innerRequire = avalon.require = function (array, factory, parentUrl, defineConfig) { - if (!isUserFirstRequire) { - requireQueue.push(avalon.slice(arguments)) - if (arguments.length <= 2) { - isUserFirstRequire = true - var queue = requireQueue.splice(0, requireQueue.length), args - while (args = queue.shift()) { - innerRequire.apply(null, args) - } - } - return - } - - if (!Array.isArray(array)) { - avalon.error("require方法的第一个å‚数应为数组 " + array) - } - var deps = [] // 放置所有ä¾èµ–项的完整路径 - var uniq = {} - var id = parentUrl || "callback" + setTimeout("1")// jshint ignore:line - defineConfig = defineConfig || {} - defineConfig.baseUrl = kernel.baseUrl - var isBuilt = !!defineConfig.built - if (parentUrl) { - defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf("/")) - defineConfig.mapUrl = parentUrl.replace(rjsext, "") - } - if (isBuilt) { - var req = makeRequest(defineConfig.defineName, defineConfig) - id = req.urlNoQuery - } else { - array.forEach(function (name) { - var req = makeRequest(name, defineConfig) - var url = fireRequest(req) //加载资æºï¼Œå¹¶è¿”回该资æºçš„å®Œæ•´åœ°å€ - if (url) { - if (!uniq[url]) { - deps.push(url) - uniq[url] = "å¸å¾’正美" //åŽ»é‡ - } - } - }) - } - - var module = modules[id] - if (!module || module.state !== 4) { - modules[id] = { - id: id, - deps: isBuilt ? array.concat() : deps, - factory: factory || noop, - state: 3 - } - } - if (!module) { - //如果此模å—是定义在å¦ä¸€ä¸ªJS文件中, 那必须等该文件加载完毕, æ‰èƒ½æ”¾åˆ°æ£€æµ‹åˆ—队中 - loadings.push(id) - } - checkDeps() - } - -//核心API之二 require - innerRequire.define = function (name, deps, factory) { //模å—å,ä¾èµ–列表,模å—本身 - if (typeof name !== "string") { - factory = deps - deps = name - name = "anonymous" - } - if (!Array.isArray(deps)) { - factory = deps - deps = [] - } - var config = { - built: !isUserFirstRequire, //用r.js打包åŽ,所有define会放到requirejsä¹‹å‰ - defineName: name - } - var args = [deps, factory, config] - factory.require = function (url) { - args.splice(2, 0, url) - if (modules[url]) { - modules[url].state = 3 //loaded - var isCycle = false - try { - isCycle = checkCycle(modules[url].deps, url) - } catch (e) { - } - if (isCycle) { - avalon.error(url + "模å—与之å‰çš„模å—存在循环ä¾èµ–,请ä¸è¦ç›´æŽ¥ç”¨script标签引入" + url + "模å—") - } - } - delete factory.require //释放内存 - innerRequire.apply(null, args) //0,1,2 --> 1,2,0 - } -//æ ¹æ®æ ‡å‡†,所有éµå¾ªW3C标准的æµè§ˆå™¨,script标签会按标签的出现顺åºæ‰§è¡Œã€‚ -//è€çš„æµè§ˆå™¨ä¸­ï¼ŒåŠ è½½ä¹Ÿæ˜¯æŒ‰é¡ºåºçš„:一个文件下载完æˆåŽï¼Œæ‰å¼€å§‹ä¸‹è½½ä¸‹ä¸€ä¸ªæ–‡ä»¶ã€‚ -//较新的æµè§ˆå™¨ä¸­ï¼ˆIE8+ ã€FireFox3.5+ ã€Chrome4+ ã€Safari4+),为了å‡å°è¯·æ±‚时间以优化体验, -//下载å¯ä»¥æ˜¯å¹¶è¡Œçš„,但是执行顺åºè¿˜æ˜¯æŒ‰ç…§æ ‡ç­¾å‡ºçŽ°çš„顺åºã€‚ -//但如果script标签是动æ€æ’入的, 就未必按照先请求先执行的原则了,目测åªæœ‰firefoxéµå®ˆ -//唯一比较一致的是,IE10+åŠå…¶ä»–标准æµè§ˆå™¨,一旦开始解æžè„šæœ¬, 就会一直堵在那里,直接脚本解æžå®Œæ¯• -//亦å³ï¼Œå…ˆè¿›å…¥loading阶段的script标签(模å—)必然会先进入loaded阶段 - var url = config.built ? "unknown" : getCurrentScript() - if (url) { - var module = modules[url] - if (module) { - module.state = 2 - } - factory.require(url) - } else {//åˆå¹¶å‰åŽçš„safari,åˆå¹¶åŽçš„IE6-9走此分支 - factorys.push(factory) - } - } -//核心API之三 require.config(settings) - innerRequire.config = kernel - //核心API之四 define.amd 标识其符åˆAMD规范 - innerRequire.define.amd = modules - - //==========================对用户é…置项进行å†åŠ å·¥========================== - var allpaths = kernel["orig.paths"] = {} - var allmaps = kernel["orig.map"] = {} - var allpackages = kernel["packages"] = [] - var allargs = kernel["orig.args"] = {} - avalon.mix(plugins, { - paths: function (hash) { - avalon.mix(allpaths, hash) - kernel.paths = makeIndexArray(allpaths) - }, - map: function (hash) { - avalon.mix(allmaps, hash) - var list = makeIndexArray(allmaps, 1, 1) - avalon.each(list, function (_, item) { - item.val = makeIndexArray(item.val) - }) - kernel.map = list - }, - packages: function (array) { - array = array.concat(allpackages) - var uniq = {} - var ret = [] - for (var i = 0, pkg; pkg = array[i++]; ) { - pkg = typeof pkg === "string" ? {name: pkg} : pkg - var name = pkg.name - if (!uniq[name]) { - var url = joinPath(pkg.location || name, pkg.main || "main") - url = url.replace(rjsext, "") - ret.push(pkg) - uniq[name] = pkg.location = url - pkg.reg = makeMatcher(name) - } - } - kernel.packages = ret.sort() - }, - urlArgs: function (hash) { - if (typeof hash === "string") { - hash = {"*": hash} - } - avalon.mix(allargs, hash) - kernel.urlArgs = makeIndexArray(allargs, 1) - }, - baseUrl: function (url) { - if (!isAbsUrl(url)) { - var baseElement = head.getElementsByTagName("base")[0] - if (baseElement) { - head.removeChild(baseElement) - } - var node = DOC.createElement("a") - node.href = url - url = getFullUrl(node, "href") - if (baseElement) { - head.insertBefore(baseElement, head.firstChild) - } - } - if (url.length > 3) - kernel.baseUrl = url - }, - shim: function (obj) { - for (var i in obj) { - var value = obj[i] - if (Array.isArray(value)) { - value = obj[i] = { - deps: value - } - } - if (!value.exportsFn && (value.exports || value.init)) { - value.exportsFn = makeExports(value) - } - } - kernel.shim = obj - } - - }) - - - //==============================内部方法================================= - function checkCycle(deps, nick) { - //检测是å¦å­˜åœ¨å¾ªçŽ¯ä¾èµ– - for (var i = 0, id; id = deps[i++]; ) { - if (modules[id].state !== 4 && - (id === nick || checkCycle(modules[id].deps, nick))) { - return true - } - } - } - - function checkFail(node, onError, fuckIE) { - var id = trimQuery(node.src) //检测是å¦æ­»é“¾ - node.onload = node.onreadystatechange = node.onerror = null - if (onError || (fuckIE && modules[id] && !modules[id].state)) { - setTimeout(function () { - head.removeChild(node) - node = null // 处ç†æ—§å¼IE下的循环引用问题 - }) - log("debug: 加载 " + id + " 失败" + onError + " " + (!modules[id].state)) - } else { - return true - } - } - - function checkDeps() { - //检测此JS模å—çš„ä¾èµ–是å¦éƒ½å·²å®‰è£…完毕,是则安装自身 - loop: for (var i = loadings.length, id; id = loadings[--i]; ) { - var obj = modules[id], - deps = obj.deps - if (!deps) - continue - for (var j = 0, key; key = deps[j]; j++) { - if (Object(modules[key]).state !== 4) { - continue loop - } - } - //如果deps是空对象或者其ä¾èµ–的模å—的状æ€éƒ½æ˜¯2 - if (obj.state !== 4) { - loadings.splice(i, 1) //必须先移除å†å®‰è£…,防止在IE下DOM树建完åŽæ‰‹åŠ¨åˆ·æ–°é¡µé¢ï¼Œä¼šå¤šæ¬¡æ‰§è¡Œå®ƒ - fireFactory(obj.id, obj.deps, obj.factory) - checkDeps() //如果æˆåŠŸ,则å†æ‰§è¡Œä¸€æ¬¡,以防有些模å—就差本模å—没有安装好 - } - } - } - - var rreadyState = /complete|loaded/ - function loadJS(url, id, callback) { - //通过scriptèŠ‚ç‚¹åŠ è½½ç›®æ ‡æ¨¡å— - var node = DOC.createElement("script") - node.className = subscribers //让getCurrentScriptåªå¤„ç†ç±»å为subscribersçš„script节点 - var supportLoad = "onload" in node - var onEvent = supportLoad ? "onload" : "onreadystatechange" - function onload() { - var factory = factorys.pop() - factory && factory.require(id) - if (callback) { - callback() - } - if (checkFail(node, false, !supportLoad)) { - log("debug: å·²æˆåŠŸåŠ è½½ " + url) - id && loadings.push(id) - checkDeps() - } - } - var index = 0, loadID - node[onEvent] = supportLoad ? onload : function () { - if (rreadyState.test(node.readyState)) { - ++index - if (index === 1) { - loadID = setTimeout(onload, 500) - } else { - clearTimeout(loadID) - onload() - } - } - } - node.onerror = function () { - checkFail(node, true) - } - - head.insertBefore(node, head.firstChild) //chrome下第二个å‚æ•°ä¸èƒ½ä¸ºnull - node.src = url //æ’入到head的第一个节点å‰ï¼Œé˜²æ­¢IE6下head标签没闭åˆå‰ä½¿ç”¨appendChild抛错 - log("debug: 正准备加载 " + url) //æ›´é‡è¦çš„是IE6下å¯ä»¥æ”¶çª„getCurrentScript的寻找范围 - } - - var resources = innerRequire.plugins = { - //三大常用资æºæ’件 js!, css!, text!, ready! - ready: { - load: noop - }, - js: { - load: function (name, req, onLoad) { - var url = req.url - var id = req.urlNoQuery - var shim = kernel.shim[name.replace(rjsext, "")] - if (shim) { //shim机制 - innerRequire(shim.deps || [], function () { - var args = avalon.slice(arguments) - loadJS(url, id, function () { - onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0) - }) - }) - } else { - loadJS(url, id) - } - } - }, - css: { - load: function (name, req, onLoad) { - var url = req.url - var node = DOC.createElement("link") - node.rel = "stylesheet" - node.href = url - head.insertBefore(node, head.firstChild) - log("debug: å·²æˆåŠŸåŠ è½½ " + url) - onLoad() - } - }, - text: { - load: function (name, req, onLoad) { - var url = req.url - var xhr = getXHR() - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - var status = xhr.status; - if (status > 399 && status < 600) { - avalon.error(url + " 对应资æºä¸å­˜åœ¨æˆ–æ²¡æœ‰å¼€å¯ CORS") - } else { - log("debug: å·²æˆåŠŸåŠ è½½ " + url) - onLoad(xhr.responseText) - } - } - } - var time = "_=" + (new Date() - 0) - var _url = url.indexOf("?") === -1 ? url + "?" + time : url + "&" + time - xhr.open("GET", _url, true) - if ("withCredentials" in xhr) {//这是处ç†è·¨åŸŸ - xhr.withCredentials = true - } - xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")//告诉åŽç«¯è¿™æ˜¯AJAX请求 - xhr.send() - log("debug: 正准备加载 " + url) - } - } - } - innerRequire.checkDeps = checkDeps - - var rquery = /(\?[^#]*)$/ - function trimQuery(url) { - return (url || "").replace(rquery, "") - } - - function isAbsUrl(path) { - //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative - return /^(?:[a-z]+:)?\/\//i.test(String(path)) - } - - function getFullUrl(node, src) { - return"1"[0] ? node[src] : node.getAttribute(src, 4) - } - - function getCurrentScript() { - // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js - var stack - try { - a.b.c() //强制报错,以便æ•èŽ·e.stack - } catch (e) { //safari5çš„sourceURL,firefoxçš„fileName,它们的效果与e.stackä¸ä¸€æ · - stack = e.stack - if (!stack && window.opera) { - //opera 9没有e.stack,但有e.Backtrace,但ä¸èƒ½ç›´æŽ¥å–å¾—,需è¦å¯¹eå¯¹è±¡è½¬å­—ç¬¦ä¸²è¿›è¡ŒæŠ½å– - stack = (String(e).match(/of linked script \S+/g) || []).join(" ") - } - } - if (stack) { - /**e.stack最åŽä¸€è¡Œåœ¨æ‰€æœ‰æ”¯æŒçš„æµè§ˆå™¨å¤§è‡´å¦‚下: - *chrome23: - * at http://113.93.50.63/data.js:4:1 - *firefox17: - *@http://113.93.50.63/query.js:4 - *opera12:http://www.oldapps.com/opera.php?system=Windows_XP - *@http://113.93.50.63/data.js:4 - *IE10: - * at Global code (http://113.93.50.63/data.js:4:1) - * //firefox4+ å¯ä»¥ç”¨document.currentScript - */ - stack = stack.split(/[@ ]/g).pop() //å–得最åŽä¸€è¡Œ,最åŽä¸€ä¸ªç©ºæ ¼æˆ–@之åŽçš„部分 - stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉æ¢è¡Œç¬¦ - return trimQuery(stack.replace(/(:\d+)?:\d+$/i, "")) //去掉行å·ä¸Žæˆ–许存在的出错字符起始ä½ç½® - } - var nodes = head.getElementsByTagName("script") //åªåœ¨head标签中寻找 - for (var i = nodes.length, node; node = nodes[--i]; ) { - if (node.className === subscribers && node.readyState === "interactive") { - var url = getFullUrl(node, "src") - return node.className = trimQuery(url) - } - } - } - - var rcallback = /^callback\d+$/ - function fireFactory(id, deps, factory) { - var module = Object(modules[id]) - module.state = 4 - for (var i = 0, array = [], d; d = deps[i++]; ) { - if (d === "exports") { - var obj = module.exports || (module.exports = {}) - array.push(obj) - } else { - array.push(modules[d].exports) - } - } - try { - var ret = factory.apply(window, array) - } catch (e) { - log("执行[" + id + "]模å—çš„factory抛错: ", e) - } - if (ret !== void 0) { - module.exports = ret - } - if (rcallback.test(id)) { - delete modules[id] - } - delete module.factory - return ret - } - function toUrl(id) { - if (id.indexOf(this.res + "!") === 0) { - id = id.slice(this.res.length + 1) //处ç†define("css!style",[], function(){})的情况 - } - var url = id - //1. 是å¦å‘½ä¸­pathsé…置项 - var usePath = 0 - var baseUrl = this.baseUrl - var rootUrl = this.parentUrl || baseUrl - eachIndexArray(id, kernel.paths, function (value, key) { - url = url.replace(key, value) - usePath = 1 - }) - //2. 是å¦å‘½ä¸­packagesé…置项 - if (!usePath) { - eachIndexArray(id, kernel.packages, function (value, key, item) { - url = url.replace(item.name, item.location) - }) - } - //3. 是å¦å‘½ä¸­mapé…置项 - if (this.mapUrl) { - eachIndexArray(this.mapUrl, kernel.map, function (array) { - eachIndexArray(url, array, function (mdValue, mdKey) { - url = url.replace(mdKey, mdValue) - rootUrl = baseUrl - }) - }) - } - var ext = this.ext - if (ext && usePath && url.slice(-ext.length) === ext) { - url = url.slice(0, -ext.length) - } - //4. 转æ¢ä¸ºç»å¯¹è·¯å¾„ - if (!isAbsUrl(url)) { - rootUrl = this.built || /^\w/.test(url) ? baseUrl : rootUrl - url = joinPath(rootUrl, url) - } - //5. 还原扩展å,query - var urlNoQuery = url + ext - url = urlNoQuery + this.query - //6. 处ç†urlArgs - eachIndexArray(id, kernel.urlArgs, function (value) { - url += (url.indexOf("?") === -1 ? "?" : "&") + value; - }) - this.url = url - return this.urlNoQuery = urlNoQuery - } - - function makeIndexArray(hash, useStar, part) { - //创建一个ç»è¿‡ç‰¹æ®Šç®—法排好åºçš„数组 - var index = hash2array(hash, useStar, part) - index.sort(descSorterByName) - return index - } - - function makeMatcher(prefix) { - return new RegExp('^' + prefix + '(/|$)') - } - - function makeExports(value) { - return function () { - var ret - if (value.init) { - ret = value.init.apply(window, arguments) - } - return ret || (value.exports && getGlobal(value.exports)) - } - } - - - function hash2array(hash, useStar, part) { - var array = []; - for (var key in hash) { - if (ohasOwn.call(hash, key)) { - var item = { - name: key, - val: hash[key] - } - array.push(item) - item.reg = key === "*" && useStar ? /^/ : makeMatcher(key) - if (part && key !== "*") { - item.reg = new RegExp('\/' + key.replace(/^\//, "") + '(/|$)') - } - } - } - return array - } - - function eachIndexArray(moduleID, array, matcher) { - array = array || [] - for (var i = 0, el; el = array[i++]; ) { - if (el.reg.test(moduleID)) { - matcher(el.val, el.name, el) - return false - } - } - } - // æ ¹æ®å…ƒç´ çš„name项进行数组字符数逆åºçš„排åºå‡½æ•° - function descSorterByName(a, b) { - var aaa = a.name - var bbb = b.name - if (bbb === "*") { - return -1 - } - if (aaa === "*") { - return 1 - } - return bbb.length - aaa.length - } - - var rdeuce = /\/\w+\/\.\./ - function joinPath(a, b) { - if (a.charAt(a.length - 1) !== "/") { - a += "/" - } - if (b.slice(0, 2) === "./") { //相对于兄弟路径 - return a + b.slice(2) - } - if (b.slice(0, 2) === "..") { //相对于父路径 - a += b - while (rdeuce.test(a)) { - a = a.replace(rdeuce, "") - } - return a - } - if (b.slice(0, 1) === "/") { - return a + b.slice(1) - } - return a + b - } - - function getGlobal(value) { - if (!value) { - return value - } - var g = window - value.split(".").forEach(function (part) { - g = g[part] - }) - return g - } - - var mainNode = DOC.scripts[DOC.scripts.length - 1] - var dataMain = mainNode.getAttribute("data-main") - if (dataMain) { - plugins.baseUrl(dataMain) - var href = kernel.baseUrl - kernel.baseUrl = href.slice(0, href.lastIndexOf("/") + 1) - loadJS(href.replace(rjsext, "") + ".js") - } else { - var loaderUrl = trimQuery(getFullUrl(mainNode, "src")) - kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1) - } -}// jshint ignore:line - -/********************************************************************* - * DOMReady * - **********************************************************************/ - -var readyList = [], isReady -var fireReady = function(fn) { - isReady = true - if (innerRequire) { - modules["domReady!"].state = 4 - innerRequire.checkDeps() - } - while(fn = readyList.shift()){ - fn(avalon) - } -} - -function doScrollCheck() { - try { //IE下通过doScrollCheck检测DOM树是å¦å»ºå®Œ - root.doScroll("left") - fireReady() - } catch (e) { - setTimeout(doScrollCheck) - } -} - -if (DOC.readyState === "complete") { - setTimeout(fireReady) //如果在domReady之外加载 -} else if (W3C) { - DOC.addEventListener("DOMContentLoaded", fireReady) -} else { - DOC.attachEvent("onreadystatechange", function() { - if (DOC.readyState === "complete") { - fireReady() - } - }) - try { - var isTop = window.frameElement === null - } catch (e) { - } - if (root.doScroll && isTop && window.external) {//fix IE iframe BUG - doScrollCheck() - } -} -avalon.bind(window, "load", fireReady) - -avalon.ready = function(fn) { - if (!isReady) { - readyList.push(fn) - } else { - fn(avalon) - } -} - -avalon.config({ - loader: true -}) - -avalon.ready(function() { - avalon.scan(DOC.body) -}) - -// Register as a named AMD module, since avalon can be concatenated with other -// files that may use define, but not via a proper concatenation script that -// understands anonymous AMD modules. A named AMD is safest and most robust -// way to register. Lowercase avalon is used because AMD module names are -// derived from file names, and Avalon is normally delivered in a lowercase -// file name. Do this after creating the global so that if an AMD module wants -// to call noConflict to hide this version of avalon, it will work. - -// Note that for maximum portability, libraries that are not avalon should -// declare themselves as anonymous modules, and avoid setting a global if an -// AMD loader is present. avalon is a special case. For more information, see -// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon - if (typeof define === "function" && define.amd) { - define("avalon", [], function() { - return avalon - }) - } -// Map over avalon in case of overwrite - var _avalon = window.avalon - avalon.noConflict = function(deep) { - if (deep && window.avalon === avalon) { - window.avalon = _avalon - } - return avalon - } -// Expose avalon identifiers, even in AMD -// and CommonJS for browser emulators - if (noGlobal === void 0) { - window.avalon = avalon - } - return avalon - +/*================================================== + Copyright (c) 2013-2015 å¸å¾’正美 and other contributors + http://www.cnblogs.com/rubylouvre/ + https://github.com/RubyLouvre + http://weibo.com/jslouvre/ + + Released under the MIT license + avalon.js 1.45 built in 2015.7.17 + support IE6+ and other browsers + ==================================================*/ +(function(global, factory) { + + if (typeof module === "object" && typeof module.exports === "object") { + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get avalon. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var avalon = require("avalon")(window); + module.exports = global.document ? factory(global, true) : function(w) { + if (!w.document) { + throw new Error("Avalon requires a window with a document") + } + return factory(w) + } + } else { + factory(global) + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function(window, noGlobal){ + +/********************************************************************* + * 全局å˜é‡åŠæ–¹æ³• * + **********************************************************************/ +var expose = new Date() - 0 +//http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function +var DOC = window.document +var head = DOC.getElementsByTagName("head")[0] //HEAD元素 +var ifGroup = head.insertBefore(document.createElement("avalon"), head.firstChild) //é¿å…IE6 base标签BUG +ifGroup.innerHTML = "X" +ifGroup.setAttribute("ms-skip", "1") +ifGroup.className = "avalonHide" +var rnative = /\[native code\]/ //判定是å¦åŽŸç”Ÿå‡½æ•° +function log() { + if (window.console && avalon.config.debug) { + // http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log + Function.apply.call(console.log, console, arguments) + } +} + + +var subscribers = "$" + expose +var otherRequire = window.require +var otherDefine = window.define +var innerRequire +var stopRepeatAssign = false +var rword = /[^, ]+/g //切割字符串为一个个å°å—,以空格或豆å·åˆ†å¼€å®ƒä»¬ï¼Œç»“åˆreplace实现字符串的forEach +var rcomplexType = /^(?:object|array)$/ +var rsvg = /^\[object SVG\w*Element\]$/ +var rwindow = /^\[object (?:Window|DOMWindow|global)\]$/ +var oproto = Object.prototype +var ohasOwn = oproto.hasOwnProperty +var serialize = oproto.toString +var ap = Array.prototype +var aslice = ap.slice +var Registry = {} //将函数æ›å…‰åˆ°æ­¤å¯¹è±¡ä¸Šï¼Œæ–¹ä¾¿è®¿é—®å™¨æ”¶é›†ä¾èµ– +var W3C = window.dispatchEvent +var root = DOC.documentElement +var avalonFragment = DOC.createDocumentFragment() +var cinerator = DOC.createElement("div") +var class2type = {} +"Boolean Number String Function Array Date RegExp Object Error".replace(rword, function (name) { + class2type["[object " + name + "]"] = name.toLowerCase() +}) + + +function noop() { +} + + +function oneObject(array, val) { + if (typeof array === "string") { + array = array.match(rword) || [] + } + var result = {}, + value = val !== void 0 ? val : 1 + for (var i = 0, n = array.length; i < n; i++) { + result[array[i]] = value + } + return result +} + +//生æˆUUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript +var generateID = function (prefix) { + prefix = prefix || "avalon" + return String(Math.random() + Math.random()).replace(/\d\.\d{4}/, prefix) +} +function IE() { + if (window.VBArray) { + var mode = document.documentMode + return mode ? mode : window.XMLHttpRequest ? 7 : 6 + } else { + return NaN + } +} +var IEVersion = IE() + +avalon = function (el) { //创建jQueryå¼çš„æ— new 实例化结构 + return new avalon.init(el) +} + +avalon.profile = function () { + if (window.console && avalon.config.profile) { + Function.apply.call(console.log, console, arguments) + } +} + +/*视æµè§ˆå™¨æƒ…况采用最快的异步回调*/ +avalon.nextTick = new function () {// jshint ignore:line + var tickImmediate = window.setImmediate + var tickObserver = window.MutationObserver + var tickPost = W3C && window.postMessage + if (tickImmediate) { + return tickImmediate.bind(window) + } + + var queue = [] + function callback() { + var n = queue.length + for (var i = 0; i < n; i++) { + queue[i]() + } + queue = queue.slice(n) + } + + if (tickObserver) { + var node = document.createTextNode("avalon") + new tickObserver(callback).observe(node, {characterData: true})// jshint ignore:line + return function (fn) { + queue.push(fn) + node.data = Math.random() + } + } + + if (tickPost) { + window.addEventListener("message", function (e) { + var source = e.source + if ((source === window || source === null) && e.data === "process-tick") { + e.stopPropagation() + callback() + } + }) + + return function (fn) { + queue.push(fn) + window.postMessage('process-tick', '*') + } + } + + return function (fn) { + setTimeout(fn, 0) + } +}// jshint ignore:line +/********************************************************************* + * avalonçš„é™æ€æ–¹æ³•å®šä¹‰åŒº * + **********************************************************************/ +avalon.init = function (el) { + this[0] = this.element = el +} +avalon.fn = avalon.prototype = avalon.init.prototype + +avalon.type = function (obj) { //å–得目标的类型 + if (obj == null) { + return String(obj) + } + // 早期的webkit内核æµè§ˆå™¨å®žçŽ°äº†å·²åºŸå¼ƒçš„ecma262v4标准,å¯ä»¥å°†æ­£åˆ™å­—é¢é‡å½“作函数使用,因此typeof在判定正则时会返回function + return typeof obj === "object" || typeof obj === "function" ? + class2type[serialize.call(obj)] || "object" : + typeof obj +} + +var isFunction = typeof alert === "object" ? function (fn) { + try { + return /^\s*\bfunction\b/.test(fn + "") + } catch (e) { + return false + } +} : function (fn) { + return serialize.call(fn) === "[object Function]" +} +avalon.isFunction = isFunction + +avalon.isWindow = function (obj) { + if (!obj) + return false + // 利用IE678 window == document为true,document == window竟然为false的神奇特性 + // 标准æµè§ˆå™¨åŠIE9,IE10等使用 正则检测 + return obj == obj.document && obj.document != obj //jshint ignore:line +} + +function isWindow(obj) { + return rwindow.test(serialize.call(obj)) +} +if (isWindow(window)) { + avalon.isWindow = isWindow +} +var enu +for (enu in avalon({})) { + break +} +var enumerateBUG = enu !== "0" //IE6下为true, 其他为false +/*判定是å¦æ˜¯ä¸€ä¸ªæœ´ç´ çš„javascript对象(Object),ä¸æ˜¯DOM对象,ä¸æ˜¯BOM对象,ä¸æ˜¯è‡ªå®šä¹‰ç±»çš„实例*/ +avalon.isPlainObject = function (obj, key) { + if (!obj || avalon.type(obj) !== "object" || obj.nodeType || avalon.isWindow(obj)) { + return false; + } + try { //IE内置对象没有constructor + if (obj.constructor && !ohasOwn.call(obj, "constructor") && !ohasOwn.call(obj.constructor.prototype, "isPrototypeOf")) { + return false; + } + } catch (e) { //IE8 9会在这里抛错 + return false; + } + if (enumerateBUG) { + for (key in obj) { + return ohasOwn.call(obj, key) + } + } + for (key in obj) { + } + return key === void 0 || ohasOwn.call(obj, key) +} +if (rnative.test(Object.getPrototypeOf)) { + avalon.isPlainObject = function (obj) { + // 简å•çš„ typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通ä¸è¿‡ + return serialize.call(obj) === "[object Object]" && Object.getPrototypeOf(obj) === oproto + } +} +//与jQuery.extend方法,å¯ç”¨äºŽæµ…æ‹·è´ï¼Œæ·±æ‹·è´ +avalon.mix = avalon.fn.mix = function () { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false + + // 如果第一个å‚数为布尔,判定是å¦æ·±æ‹·è´ + if (typeof target === "boolean") { + deep = target + target = arguments[1] || {} + i++ + } + + //ç¡®ä¿æŽ¥å—方为一个å¤æ‚çš„æ•°æ®ç±»åž‹ + if (typeof target !== "object" && !isFunction(target)) { + target = {} + } + + //如果åªæœ‰ä¸€ä¸ªå‚数,那么新æˆå‘˜æ·»åŠ äºŽmix所在的对象上 + if (i === length) { + target = this + i-- + } + + for (; i < length; i++) { + //åªå¤„ç†éžç©ºå‚æ•° + if ((options = arguments[i]) != null) { + for (name in options) { + src = target[name] + try { + copy = options[name] //当options为VBS对象时报错 + } catch (e) { + continue + } + + // 防止环引用 + if (target === copy) { + continue + } + if (deep && copy && (avalon.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { + + if (copyIsArray) { + copyIsArray = false + clone = src && Array.isArray(src) ? src : [] + + } else { + clone = src && avalon.isPlainObject(src) ? src : {} + } + + target[name] = avalon.mix(deep, clone, copy) + } else if (copy !== void 0) { + target[name] = copy + } + } + } + } + return target +} + +function _number(a, len) { //用于模拟slice, splice的效果 + a = Math.floor(a) || 0 + return a < 0 ? Math.max(len + a, 0) : Math.min(a, len); +} +avalon.mix({ + rword: rword, + subscribers: subscribers, + version: 1.45, + ui: {}, + log: log, + slice: W3C ? function (nodes, start, end) { + return aslice.call(nodes, start, end) + } : function (nodes, start, end) { + var ret = [] + var len = nodes.length + if (end === void 0) + end = len + if (typeof end === "number" && isFinite(end)) { + start = _number(start, len) + end = _number(end, len) + for (var i = start; i < end; ++i) { + ret[i - start] = nodes[i] + } + } + return ret + }, + noop: noop, + /*如果ä¸ç”¨Error对象å°è£…一下,str在控制å°ä¸‹å¯èƒ½ä¼šä¹±ç */ + error: function (str, e) { + throw (e || Error)(str) + }, + /*将一个以空格或逗å·éš”开的字符串或数组,转æ¢æˆä¸€ä¸ªé”®å€¼éƒ½ä¸º1的对象*/ + oneObject: oneObject, + /* avalon.range(10) + => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + avalon.range(1, 11) + => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + avalon.range(0, 30, 5) + => [0, 5, 10, 15, 20, 25] + avalon.range(0, -10, -1) + => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] + avalon.range(0) + => []*/ + range: function (start, end, step) { // 用于生æˆæ•´æ•°æ•°ç»„ + step || (step = 1) + if (end == null) { + end = start || 0 + start = 0 + } + var index = -1, + length = Math.max(0, Math.ceil((end - start) / step)), + result = new Array(length) + while (++index < length) { + result[index] = start + start += step + } + return result + }, + eventHooks: [], + /*绑定事件*/ + bind: function(el, type, fn, phase) { + var hooks = avalon.eventHooks + var hook = hooks[type] + if (typeof hook === "object") { + type = hook.type + if (hook.deel) { + fn = hook.deel(el, type, fn, phase) + } + } + var callback = W3C ? fn : function(e) { + fn.call(el, fixEvent(e)); + } + if (W3C) { + el.addEventListener(type, callback, !!phase) + } else { + el.attachEvent("on" + type, callback) + } + return callback + }, + /*å¸è½½äº‹ä»¶*/ + unbind: function(el, type, fn, phase) { + var hooks = avalon.eventHooks + var hook = hooks[type] + var callback = fn || noop + if (typeof hook === "object") { + type = hook.type + if (hook.deel) { + fn = hook.deel(el, type, fn, false) + } + } + if (W3C) { + el.removeEventListener(type, callback, !!phase) + } else { + el.detachEvent("on" + type, callback) + } + }, + /*读写删除元素节点的样å¼*/ + css: function (node, name, value) { + if (node instanceof avalon) { + node = node[0] + } + var prop = /[_-]/.test(name) ? camelize(name) : name, fn + name = avalon.cssName(prop) || prop + if (value === void 0 || typeof value === "boolean") { //获å–æ ·å¼ + fn = cssHooks[prop + ":get"] || cssHooks["@:get"] + if (name === "background") { + name = "backgroundColor" + } + var val = fn(node, name) + return value === true ? parseFloat(val) || 0 : val + } else if (value === "") { //è¯·é™¤æ ·å¼ + node.style[name] = "" + } else { //è®¾ç½®æ ·å¼ + if (value == null || value !== value) { + return + } + if (isFinite(value) && !avalon.cssNumber[prop]) { + value += "px" + } + fn = cssHooks[prop + ":set"] || cssHooks["@:set"] + fn(node, name, value) + } + }, + /*é历数组与对象,回调的第一个å‚数为索引或键å,第二个或元素或键值*/ + each: function (obj, fn) { + if (obj) { //排除null, undefined + var i = 0 + if (isArrayLike(obj)) { + for (var n = obj.length; i < n; i++) { + if (fn(i, obj[i]) === false) + break + } + } else { + for (i in obj) { + if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) { + break + } + } + } + } + }, + //收集元素的data-{{prefix}}-*属性,并转æ¢ä¸ºå¯¹è±¡ + getWidgetData: function (elem, prefix) { + var raw = avalon(elem).data() + var result = {} + for (var i in raw) { + if (i.indexOf(prefix) === 0) { + result[i.replace(prefix, "").replace(/\w/, function (a) { + return a.toLowerCase() + })] = raw[i] + } + } + return result + }, + Array: { + /*åªæœ‰å½“å‰æ•°ç»„ä¸å­˜åœ¨æ­¤å…ƒç´ æ—¶åªæ·»åŠ å®ƒ*/ + ensure: function (target, item) { + if (target.indexOf(item) === -1) { + return target.push(item) + } + }, + /*移除数组中指定ä½ç½®çš„元素,返回布尔表示æˆåŠŸä¸Žå¦*/ + removeAt: function (target, index) { + return !!target.splice(index, 1).length + }, + /*移除数组中第一个匹é…ä¼ å‚的那个元素,返回布尔表示æˆåŠŸä¸Žå¦*/ + remove: function (target, item) { + var index = target.indexOf(item) + if (~index) + return avalon.Array.removeAt(target, index) + return false + } + } +}) + +var bindingHandlers = avalon.bindingHandlers = {} +var bindingExecutors = avalon.bindingExecutors = {} + +/*判定是å¦ç±»æ•°ç»„,如节点集åˆï¼Œçº¯æ•°ç»„,arguments与拥有éžè´Ÿæ•´æ•°çš„length属性的纯JS对象*/ +function isArrayLike(obj) { + if (!obj) + return false + var n = obj.length + if (n === (n >>> 0)) { //检测length属性是å¦ä¸ºéžè´Ÿæ•´æ•° + var type = serialize.call(obj).slice(8, -1) + if (/(?:regexp|string|function|window|global)$/i.test(type)) + return false + if (type === "Array") + return true + try { + if ({}.propertyIsEnumerable.call(obj, "length") === false) { //如果是原生对象 + return /^\s?function/.test(obj.item || obj.callee) + } + return true + } catch (e) { //IEçš„NodeList直接抛错 + return !obj.window //IE6-8 window + } + } + return false +} + + +// https://github.com/rsms/js-lru +var Cache = new function() {// jshint ignore:line + function LRU(maxLength) { + this.size = 0 + this.limit = maxLength + this.head = this.tail = void 0 + this._keymap = {} + } + + var p = LRU.prototype + + p.put = function(key, value) { + var entry = { + key: key, + value: value + } + this._keymap[key] = entry + if (this.tail) { + this.tail.newer = entry + entry.older = this.tail + } else { + this.head = entry + } + this.tail = entry + if (this.size === this.limit) { + this.shift() + } else { + this.size++ + } + return value + } + + p.shift = function() { + var entry = this.head + if (entry) { + this.head = this.head.newer + this.head.older = + entry.newer = + entry.older = + this._keymap[entry.key] = void 0 + } + } + p.get = function(key) { + var entry = this._keymap[key] + if (entry === void 0) + return + if (entry === this.tail) { + return entry.value + } + // HEAD--------------TAIL + // <.older .newer> + // <--- add direction -- + // A B C E + if (entry.newer) { + if (entry === this.head) { + this.head = entry.newer + } + entry.newer.older = entry.older // C <-- E. + } + if (entry.older) { + entry.older.newer = entry.newer // C. --> E + } + entry.newer = void 0 // D --x + entry.older = this.tail // D. --> E + if (this.tail) { + this.tail.newer = entry // E. <-- D + } + this.tail = entry + return entry.value + } + return LRU +}// jshint ignore:line + +/********************************************************************* + * javascript åº•å±‚è¡¥ä¸ * + **********************************************************************/ +if (!"å¸å¾’正美".trim) { + var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g + String.prototype.trim = function () { + return this.replace(rtrim, "") + } +} +var hasDontEnumBug = !({ + 'toString': null +}).propertyIsEnumerable('toString'), + hasProtoEnumBug = (function () { + }).propertyIsEnumerable('prototype'), + dontEnums = [ + "toString", + "toLocaleString", + "valueOf", + "hasOwnProperty", + "isPrototypeOf", + "propertyIsEnumerable", + "constructor" + ], + dontEnumsLength = dontEnums.length; +if (!Object.keys) { + Object.keys = function (object) { //ecma262v5 15.2.3.14 + var theKeys = [] + var skipProto = hasProtoEnumBug && typeof object === "function" + if (typeof object === "string" || (object && object.callee)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)) + } + } else { + for (var name in object) { + if (!(skipProto && name === "prototype") && ohasOwn.call(object, name)) { + theKeys.push(String(name)) + } + } + } + + if (hasDontEnumBug) { + var ctor = object.constructor, + skipConstructor = ctor && ctor.prototype === object + for (var j = 0; j < dontEnumsLength; j++) { + var dontEnum = dontEnums[j] + if (!(skipConstructor && dontEnum === "constructor") && ohasOwn.call(object, dontEnum)) { + theKeys.push(dontEnum) + } + } + } + return theKeys + } +} +if (!Array.isArray) { + Array.isArray = function (a) { + return serialize.call(a) === "[object Array]" + } +} + +if (!noop.bind) { + Function.prototype.bind = function (scope) { + if (arguments.length < 2 && scope === void 0) + return this + var fn = this, + argv = arguments + return function () { + var args = [], + i + for (i = 1; i < argv.length; i++) + args.push(argv[i]) + for (i = 0; i < arguments.length; i++) + args.push(arguments[i]) + return fn.apply(scope, args) + } + } +} + +function iterator(vars, body, ret) { + var fun = 'for(var ' + vars + 'i=0,n = this.length; i < n; i++){' + body.replace('_', '((i in this) && fn.call(scope,this[i],i,this))') + '}' + ret + /* jshint ignore:start */ + return Function("fn,scope", fun) + /* jshint ignore:end */ +} +if (!rnative.test([].map)) { + avalon.mix(ap, { + //定ä½æ“作,返回数组中第一个等于给定å‚数的元素的索引值。 + indexOf: function (item, index) { + var n = this.length, + i = ~~index + if (i < 0) + i += n + for (; i < n; i++) + if (this[i] === item) + return i + return -1 + }, + //定ä½æ“作,åŒä¸Šï¼Œä¸è¿‡æ˜¯ä»ŽåŽé历。 + lastIndexOf: function (item, index) { + var n = this.length, + i = index == null ? n - 1 : index + if (i < 0) + i = Math.max(0, n + i) + for (; i >= 0; i--) + if (this[i] === item) + return i + return -1 + }, + //迭代æ“作,将数组的元素挨个儿传入一个函数中执行。Prototype.js的对应å字为each。 + forEach: iterator("", '_', ""), + //迭代类 在数组中的æ¯ä¸ªé¡¹ä¸Šè¿è¡Œä¸€ä¸ªå‡½æ•°ï¼Œå¦‚果此函数的值为真,则此元素作为新数组的元素收集起æ¥ï¼Œå¹¶è¿”回新数组 + filter: iterator('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r'), + //收集æ“作,将数组的元素挨个儿传入一个函数中执行,然åŽæŠŠå®ƒä»¬çš„返回值组æˆä¸€ä¸ªæ–°æ•°ç»„返回。Prototype.js的对应å字为collect。 + map: iterator('r=[],', 'r[i]=_', 'return r'), + //åªè¦æ•°ç»„中有一个元素满足æ¡ä»¶ï¼ˆæ”¾è¿›ç»™å®šå‡½æ•°è¿”回true),那么它就返回true。Prototype.js的对应å字为any。 + some: iterator("", 'if(_)return true', 'return false'), + //åªæœ‰æ•°ç»„中的元素都满足æ¡ä»¶ï¼ˆæ”¾è¿›ç»™å®šå‡½æ•°è¿”回true),它æ‰è¿”回true。Prototype.js的对应å字为all。 + every: iterator("", 'if(!_)return false', 'return true') + }) +} +/********************************************************************* + * DOM åº•å±‚è¡¥ä¸ * + **********************************************************************/ + +function fixContains(root, el) { + try { //IE6-8,游离于DOM树外的文本节点,访问parentNode有时会抛错 + while ((el = el.parentNode)) + if (el === root) + return true + return false + } catch (e) { + return false + } +} +avalon.contains = fixContains +//IE6-11的文档对象没有contains +if (!DOC.contains) { + DOC.contains = function (b) { + return fixContains(DOC, b) + } +} + +function outerHTML() { + return new XMLSerializer().serializeToString(this) +} + +if (window.SVGElement) { + //safari5+是把contains方法放在Element.prototype上而ä¸æ˜¯Node.prototype + if (!DOC.createTextNode("x").contains) { + Node.prototype.contains = function (arg) {//IE6-8没有Node对象 + return !!(this.compareDocumentPosition(arg) & 16) + } + } + var svgns = "http://www.w3.org/2000/svg" + var svg = DOC.createElementNS(svgns, "svg") + svg.innerHTML = '' + if (!rsvg.test(svg.firstChild)) { // #409 + function enumerateNode(node, targetNode) {// jshint ignore:line + if (node && node.childNodes) { + var nodes = node.childNodes + for (var i = 0, el; el = nodes[i++]; ) { + if (el.tagName) { + var svg = DOC.createElementNS(svgns, + el.tagName.toLowerCase()) + ap.forEach.call(el.attributes, function (attr) { + svg.setAttribute(attr.name, attr.value) //å¤åˆ¶å±žæ€§ + })// jshint ignore:line + // 递归处ç†å­èŠ‚点 + enumerateNode(el, svg) + targetNode.appendChild(svg) + } + } + } + } + Object.defineProperties(SVGElement.prototype, { + "outerHTML": {//IE9-11,firefoxä¸æ”¯æŒSVG元素的innerHTML,outerHTML属性 + enumerable: true, + configurable: true, + get: outerHTML, + set: function (html) { + var tagName = this.tagName.toLowerCase(), + par = this.parentNode, + frag = avalon.parseHTML(html) + // æ“作的svg,直接æ’å…¥ + if (tagName === "svg") { + par.insertBefore(frag, this) + // svg节点的å­èŠ‚点类似 + } else { + var newFrag = DOC.createDocumentFragment() + enumerateNode(frag, newFrag) + par.insertBefore(newFrag, this) + } + par.removeChild(this) + } + }, + "innerHTML": { + enumerable: true, + configurable: true, + get: function () { + var s = this.outerHTML + var ropen = new RegExp("<" + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', "i") + var rclose = new RegExp("<\/" + this.nodeName + ">$", "i") + return s.replace(ropen, "").replace(rclose, "") + }, + set: function (html) { + if (avalon.clearHTML) { + avalon.clearHTML(this) + var frag = avalon.parseHTML(html) + enumerateNode(frag, this) + } + } + } + }) + } +} +if (!root.outerHTML && window.HTMLElement) { //firefox 到11æ—¶æ‰æœ‰outerHTML + HTMLElement.prototype.__defineGetter__("outerHTML", outerHTML); +} + + +//============================= event binding ======================= +var rmouseEvent = /^(?:mouse|contextmenu|drag)|click/ +function fixEvent(event) { + var ret = {} + for (var i in event) { + ret[i] = event[i] + } + var target = ret.target = event.srcElement + if (event.type.indexOf("key") === 0) { + ret.which = event.charCode != null ? event.charCode : event.keyCode + } else if (rmouseEvent.test(event.type)) { + var doc = target.ownerDocument || DOC + var box = doc.compatMode === "BackCompat" ? doc.body : doc.documentElement + ret.pageX = event.clientX + (box.scrollLeft >> 0) - (box.clientLeft >> 0) + ret.pageY = event.clientY + (box.scrollTop >> 0) - (box.clientTop >> 0) + ret.wheelDeltaY = ret.wheelDelta + ret.wheelDeltaX = 0 + } + ret.timeStamp = new Date() - 0 + ret.originalEvent = event + ret.preventDefault = function () { //阻止默认行为 + event.returnValue = false + } + ret.stopPropagation = function () { //阻止事件在DOM树中的传播 + event.cancelBubble = true + } + return ret +} + +var eventHooks = avalon.eventHooks +//针对firefox, chrome修正mouseenter, mouseleave +if (!("onmouseenter" in root)) { + avalon.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" + }, function (origType, fixType) { + eventHooks[origType] = { + type: fixType, + deel: function (elem, _, fn) { + return function (e) { + var t = e.relatedTarget + if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) { + delete e.type + e.type = origType + return fn.call(elem, e) + } + } + } + } + }) +} +//针对IE9+, w3c修正animationend +avalon.each({ + AnimationEvent: "animationend", + WebKitAnimationEvent: "webkitAnimationEnd" +}, function (construct, fixType) { + if (window[construct] && !eventHooks.animationend) { + eventHooks.animationend = { + type: fixType + } + } +}) +//针对IE6-8修正input +if (!("oninput" in DOC.createElement("input"))) { + eventHooks.input = { + type: "propertychange", + deel: function (elem, _, fn) { + return function (e) { + if (e.propertyName === "value") { + e.type = "input" + return fn.call(elem, e) + } + } + } + } +} +if (DOC.onmousewheel === void 0) { + /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120 + firefox DOMMouseScroll detail 下3 上-3 + firefox wheel detlaY 下3 上-3 + IE9-11 wheel deltaY 下40 上-40 + chrome wheel deltaY 下100 上-100 */ + var fixWheelType = DOC.onwheel !== void 0 ? "wheel" : "DOMMouseScroll" + var fixWheelDelta = fixWheelType === "wheel" ? "deltaY" : "detail" + eventHooks.mousewheel = { + type: fixWheelType, + deel: function (elem, _, fn) { + return function (e) { + e.wheelDeltaY = e.wheelDelta = e[fixWheelDelta] > 0 ? -120 : 120 + e.wheelDeltaX = 0 + if (Object.defineProperty) { + Object.defineProperty(e, "type", { + value: "mousewheel" + }) + } + fn.call(elem, e) + } + } + } +} + + + +/********************************************************************* + * é…置系统 * + **********************************************************************/ + +function kernel(settings) { + for (var p in settings) { + if (!ohasOwn.call(settings, p)) + continue + var val = settings[p] + if (typeof kernel.plugins[p] === "function") { + kernel.plugins[p](val) + } else if (typeof kernel[p] === "object") { + avalon.mix(kernel[p], val) + } else { + kernel[p] = val + } + } + return this +} +var openTag, closeTag, rexpr, rexprg, rbind, rregexp = /[-.*+?^${}()|[\]\/\\]/g + +function escapeRegExp(target) { + //http://stevenlevithan.com/regex/xregexp/ + //将字符串安全格å¼åŒ–为正则表达å¼çš„æºç  + return (target + "").replace(rregexp, "\\$&") +} + +var plugins = { + loader: function (builtin) { + var flag = innerRequire && builtin + window.require = flag ? innerRequire : otherRequire + window.define = flag ? innerRequire.define : otherDefine + }, + interpolate: function (array) { + openTag = array[0] + closeTag = array[1] + if (openTag === closeTag) { + throw new SyntaxError("openTag!==closeTag") + var test = openTag + "test" + closeTag + cinerator.innerHTML = test + if (cinerator.innerHTML !== test && cinerator.innerHTML.indexOf("<") > -1) { + throw new SyntaxError("此定界符ä¸åˆæ³•") + } + cinerator.innerHTML = "" + } + var o = escapeRegExp(openTag), + c = escapeRegExp(closeTag) + rexpr = new RegExp(o + "(.*?)" + c) + rexprg = new RegExp(o + "(.*?)" + c, "g") + rbind = new RegExp(o + ".*?" + c + "|\\sms-") + } +} + +kernel.debug = true +kernel.plugins = plugins +kernel.plugins['interpolate'](["{{", "}}"]) +kernel.paths = {} +kernel.shim = {} +kernel.maxRepeatSize = 100 +avalon.config = kernel +var ravalon = /(\w+)\[(avalonctrl)="(\S+)"\]/ +var findNodes = DOC.querySelectorAll ? function(str) { + return DOC.querySelectorAll(str) +} : function(str) { + var match = str.match(ravalon) + var all = DOC.getElementsByTagName(match[1]) + var nodes = [] + for (var i = 0, el; el = all[i++]; ) { + if (el.getAttribute(match[2]) === match[3]) { + nodes.push(el) + } + } + return nodes +} +/********************************************************************* + * 事件总线 * + **********************************************************************/ +var EventBus = { + $watch: function (type, callback) { + if (typeof callback === "function") { + var callbacks = this.$events[type] + if (callbacks) { + callbacks.push(callback) + } else { + this.$events[type] = [callback] + } + } else { //é‡æ–°å¼€å§‹ç›‘å¬æ­¤VM的第一é‡ç®€å•å±žæ€§çš„å˜åŠ¨ + this.$events = this.$watch.backup + } + return this + }, + $unwatch: function (type, callback) { + var n = arguments.length + if (n === 0) { //让此VM的所有$watch回调无效化 + this.$watch.backup = this.$events + this.$events = {} + } else if (n === 1) { + this.$events[type] = [] + } else { + var callbacks = this.$events[type] || [] + var i = callbacks.length + while (~--i < 0) { + if (callbacks[i] === callback) { + return callbacks.splice(i, 1) + } + } + } + return this + }, + $fire: function (type) { + var special, i, v, callback + if (/^(\w+)!(\S+)$/.test(type)) { + special = RegExp.$1 + type = RegExp.$2 + } + var events = this.$events + if (!events) + return + var args = aslice.call(arguments, 1) + var detail = [type].concat(args) + if (special === "all") { + for (i in avalon.vmodels) { + v = avalon.vmodels[i] + if (v !== this) { + v.$fire.apply(v, detail) + } + } + } else if (special === "up" || special === "down") { + var elements = events.expr ? findNodes(events.expr) : [] + if (elements.length === 0) + return + for (i in avalon.vmodels) { + v = avalon.vmodels[i] + if (v !== this) { + if (v.$events.expr) { + var eventNodes = findNodes(v.$events.expr) + if (eventNodes.length === 0) { + continue + } + //循环两个vmodel中的节点,查找匹é…(å‘上匹é…或者å‘下匹é…)的节点并设置标识 + /* jshint ignore:start */ + ap.forEach.call(eventNodes, function (node) { + ap.forEach.call(elements, function (element) { + var ok = special === "down" ? element.contains(node) : //å‘下æ•èŽ· + node.contains(element) //å‘上冒泡 + if (ok) { + node._avalon = v //符åˆæ¡ä»¶çš„加一个标识 + } + }); + }) + /* jshint ignore:end */ + } + } + } + var nodes = DOC.getElementsByTagName("*") //å®žçŽ°èŠ‚ç‚¹æŽ’åº + var alls = [] + ap.forEach.call(nodes, function (el) { + if (el._avalon) { + alls.push(el._avalon) + el._avalon = "" + el.removeAttribute("_avalon") + } + }) + if (special === "up") { + alls.reverse() + } + for (i = 0; callback = alls[i++]; ) { + if (callback.$fire.apply(callback, detail) === false) { + break + } + } + } else { + var callbacks = events[type] || [] + var all = events.$all || [] + for (i = 0; callback = callbacks[i++]; ) { + if (isFunction(callback)) + callback.apply(this, args) + } + for (i = 0; callback = all[i++]; ) { + if (isFunction(callback)) + callback.apply(this, arguments) + } + } + } +} + +/********************************************************************* + * modelFactory * + **********************************************************************/ +//avalon最核心的方法的两个方法之一(å¦ä¸€ä¸ªæ˜¯avalon.scan),返回一个ViewModel(VM) +var VMODELS = avalon.vmodels = {} //所有vmodel都储存在这里 +avalon.define = function (id, factory) { + var $id = id.$id || id + if (!$id) { + log("warning: vm必须指定$id") + } + if (VMODELS[$id]) { + log("warning: " + $id + " å·²ç»å­˜åœ¨äºŽavalon.vmodels中") + } + if (typeof id === "object") { + var model = modelFactory(id) + } else { + var scope = { + $watch: noop + } + factory(scope) //得到所有定义 + + model = modelFactory(scope) //å·å¤©æ¢æ—¥ï¼Œå°†scopeæ¢ä¸ºmodel + stopRepeatAssign = true + factory(model) + stopRepeatAssign = false + } + model.$id = $id + return VMODELS[$id] = model +} + +//一些ä¸éœ€è¦è¢«ç›‘å¬çš„属性 +var $$skipArray = String("$id,$watch,$unwatch,$fire,$events,$model,$skipArray,$proxy,$reinitialize,$propertyNames").match(rword) +var defineProperty = Object.defineProperty +var canHideOwn = true +//如果æµè§ˆå™¨ä¸æ”¯æŒecma262v5çš„Object.defineProperties或者存在BUG,比如IE8 +//标准æµè§ˆå™¨ä½¿ç”¨__defineGetter__, __defineSetter__实现 +try { + defineProperty({}, "_", { + value: "x" + }) + var defineProperties = Object.defineProperties +} catch (e) { + canHideOwn = false +} + +function modelFactory(source, $special, $model) { + if (Array.isArray(source)) { + var arr = source.concat() + source.length = 0 + var collection = arrayFactory(source) + collection.pushArray(arr) + return collection + } + //0 null undefined || Node || VModel(fix IE6-8 createWithProxy $val: val引å‘çš„BUG) + if (!source || source.nodeType > 0 || (source.$id && source.$events)) { + return source + } + var $skipArray = Array.isArray(source.$skipArray) ? source.$skipArray : [] + $skipArray.$special = $special || {} //强制è¦ç›‘å¬çš„属性 + var $vmodel = {} //è¦è¿”回的对象, 它在IE6-8下å¯èƒ½è¢«å·é¾™è½¬å‡¤ + $model = $model || {} //vmodels.$model属性 + var $events = {} //vmodel.$events属性 + var accessors = {} //监控属性 + var computed = [] + $$skipArray.forEach(function (name) { + delete source[name] + }) + var names = Object.keys(source) + /* jshint ignore:start */ + names.forEach(function (name, accessor) { + var val = source[name] + $model[name] = val + if (isObservable(name, val, $skipArray)) { + //总共产生三ç§accessor + $events[name] = [] + var valueType = avalon.type(val) + //总共产生三ç§accessor + if (valueType === "object" && isFunction(val.get) && Object.keys(val).length <= 2) { + accessor = makeComputedAccessor(name, val) + computed.push(accessor) + } else if (rcomplexType.test(valueType)) { + accessor = makeComplexAccessor(name, val, valueType, $events[name]) + } else { + accessor = makeSimpleAccessor(name, val) + } + accessors[name] = accessor + } + }) + /* jshint ignore:end */ + + $vmodel = defineProperties($vmodel, descriptorFactory(accessors), source) //生æˆä¸€ä¸ªç©ºçš„ViewModel + for (var i = 0; i < names.length; i++) { + var name = names[i] + if (!accessors[name]) { + $vmodel[name] = source[name] + } + } + //添加$id, $model, $events, $watch, $unwatch, $fire + $vmodel.$propertyNames = names.join("­") + $vmodel.$id = generateID() + $vmodel.$model = $model + $vmodel.$events = $events + for (i in EventBus) { + var fn = EventBus[i] + if (!W3C) { //在IE6-8下,VB对象的方法里的this并ä¸æŒ‡å‘自身,需è¦ç”¨bind处ç†ä¸€ä¸‹ + fn = fn.bind($vmodel) + } + $vmodel[i] = fn + } + if (canHideOwn) { + Object.defineProperty($vmodel, "hasOwnProperty", hasOwnDescriptor) + } else { + /* jshint ignore:start */ + $vmodel.hasOwnProperty = function (name) { + return name in $vmodel.$model + } + /* jshint ignore:end */ + } + + $vmodel.$reinitialize = function () { + computed.forEach(function (accessor) { + delete accessor._value + delete accessor.oldArgs + accessor.digest = function () { + accessor.call($vmodel) + } + dependencyDetection.begin({ + callback: function (vm, dependency) {//dependency为一个accessor + var name = dependency._name + if (dependency !== accessor) { + var list = vm.$events[name] + injectDependency(list, accessor.digest) + } + } + }) + try { + accessor.get.call($vmodel) + } finally { + dependencyDetection.end() + } + }) + } + $vmodel.$reinitialize() + return $vmodel +} + +var hasOwnDescriptor = { + value: function (name) { + return name in this.$model + }, + writable: false, + enumerable: false, + configurable: true +} +//创建一个简å•è®¿é—®å™¨ +function makeSimpleAccessor(name, value) { + function accessor(value) { + var oldValue = accessor._value + if (arguments.length > 0) { + if (!stopRepeatAssign && !isEqual(value, oldValue)) { + accessor.updateValue(this, value) + accessor.notify(this, value, oldValue) + } + return this + } else { + dependencyDetection.collectDependency(this, accessor) + return oldValue + } + } + accessorFactory(accessor, name) + accessor._value = value + return accessor; +} + +//创建一个计算访问器 +function makeComputedAccessor(name, options) { + function accessor(value) {//计算属性 + var oldValue = accessor._value + var init = ("_value" in accessor) + if (arguments.length > 0) { + if (stopRepeatAssign) { + return this + } + if (typeof accessor.set === "function") { + if (accessor.oldArgs !== value) { + accessor.oldArgs = value + var $events = this.$events + var lock = $events[name] + $events[name] = [] //清空回调,防止内部冒泡而触å‘多次$fire + accessor.set.call(this, value) + $events[name] = lock + value = accessor.get.call(this) + if (value !== oldValue) { + accessor.updateValue(this, value) + accessor.notify(this, value, oldValue) //触å‘$watch回调 + } + } + } + return this + } else { + //å°†ä¾èµ–于自己的高层访问器或视图刷新函数(以绑定对象形å¼ï¼‰æ”¾åˆ°è‡ªå·±çš„订阅数组中 + //将自己注入到低层访问器的订阅数组中 + value = accessor.get.call(this) + accessor.updateValue(this, value) + if (init && oldValue !== value) { + accessor.notify(this, value, oldValue) //触å‘$watch回调 + } + return value + } + } + accessor.set = options.set + accessor.get = options.get + accessorFactory(accessor, name) + return accessor +} + +//创建一个å¤æ‚访问器 +function makeComplexAccessor(name, initValue, valueType, list) { + function accessor(value) { + var oldValue = accessor._value + + var son = accessor._vmodel + if (arguments.length > 0) { + if (stopRepeatAssign) { + return this + } + if (valueType === "array") { + var a = son, b = value, + an = a.length, + bn = b.length + a.$lock = true + if (an > bn) { + a.splice(bn, an - bn) + } else if (bn > an) { + a.push.apply(a, b.slice(an)) + } + var n = Math.min(an, bn) + for (var i = 0; i < n; i++) { + a.set(i, b[i]) + } + delete a.$lock + a._fire("set") + } else if (valueType === "object") { + var newPropertyNames = Object.keys(value).join("­") + if (son.$propertyNames === newPropertyNames) { + for (i in value) { + son[i] = value[i] + } + } else { + var sson = accessor._vmodel = modelFactory(value) + var sevent = sson.$events + var oevent = son.$events + for (var i in sevent) { + var arr = sevent[i] + if (Array.isArray(arr)) { + arr = arr.concat(oevent[i]) + } + } + sevent[subscribers] = oevent[subscribers] + sson.$proxy = son.$proxy + son = sson + } + } + accessor.updateValue(this, son.$model) + accessor.notify(this, this._value, oldValue) + return this + } else { + dependencyDetection.collectDependency(this, accessor) + return son + } + } + accessorFactory(accessor, name) + var son = accessor._vmodel = modelFactory(initValue) + son.$events[subscribers] = list + return accessor +} + +function globalUpdateValue(vmodel, value) { + vmodel.$model[this._name] = this._value = value +} + +function globalNotify(vmodel, value, oldValue) { + var name = this._name + var array = vmodel.$events[name] //刷新值 + if (array) { + fireDependencies(array) //åŒæ­¥è§†å›¾ + EventBus.$fire.call(vmodel, name, value, oldValue) //触å‘$watch回调 + } +} + +function accessorFactory(accessor, name) { + accessor._name = name + //åŒæ—¶æ›´æ–°_value与model + accessor.updateValue = globalUpdateValue + accessor.notify = globalNotify +} + +//比较两个值是å¦ç›¸ç­‰ +var isEqual = Object.is || function (v1, v2) { + if (v1 === 0 && v2 === 0) { + return 1 / v1 === 1 / v2 + } else if (v1 !== v1) { + return v2 !== v2 + } else { + return v1 === v2 + } +} + +function isObservable(name, value, $skipArray) { + if (isFunction(value) || value && value.nodeType) { + return false + } + if ($skipArray.indexOf(name) !== -1) { + return false + } + var $special = $skipArray.$special + if (name && name.charAt(0) === "$" && !$special[name]) { + return false + } + return true +} + +var descriptorFactory = W3C ? function (obj) { + var descriptors = {} + for (var i in obj) { + descriptors[i] = { + get: obj[i], + set: obj[i], + enumerable: true, + configurable: true + } + } + return descriptors +} : function (a) { + return a +} + +//===================ä¿®å¤æµè§ˆå™¨å¯¹Object.defineProperties的支æŒ================= +if (!canHideOwn) { + if ("__defineGetter__" in avalon) { + defineProperty = function (obj, prop, desc) { + if ('value' in desc) { + obj[prop] = desc.value + } + if ("get" in desc) { + obj.__defineGetter__(prop, desc.get) + } + if ('set' in desc) { + obj.__defineSetter__(prop, desc.set) + } + return obj + } + defineProperties = function (obj, descs) { + for (var prop in descs) { + if (descs.hasOwnProperty(prop)) { + defineProperty(obj, prop, descs[prop]) + } + } + return obj + } + } + if (IEVersion) { + var VBClassPool = {} + window.execScript([// jshint ignore:line + "Function parseVB(code)", + "\tExecuteGlobal(code)", + "End Function" //转æ¢ä¸€æ®µæ–‡æœ¬ä¸ºVBä»£ç  + ].join("\n"), "VBScript") + function VBMediator(instance, accessors, name, value) {// jshint ignore:line + var accessor = accessors[name] + if (arguments.length === 4) { + accessor.call(instance, value) + } else { + return accessor.call(instance) + } + } + defineProperties = function (name, accessors, properties) { + // jshint ignore:line + var buffer = [] + buffer.push( + "\r\n\tPrivate [__data__], [__proxy__]", + "\tPublic Default Function [__const__](d, p)", + "\t\tSet [__data__] = d: set [__proxy__] = p", + "\t\tSet [__const__] = Me", //链å¼è°ƒç”¨ + "\tEnd Function") + //添加普通属性,因为VBScript对象ä¸èƒ½åƒJS那样éšæ„增删属性,必须在这里预先定义好 + for (name in properties) { + if (!accessors.hasOwnProperty(name)) { + buffer.push("\tPublic [" + name + "]") + } + } + $$skipArray.forEach(function (name) { + if (!accessors.hasOwnProperty(name)) { + buffer.push("\tPublic [" + name + "]") + } + }) + buffer.push("\tPublic [" + 'hasOwnProperty' + "]") + //添加访问器属性 + for (name in accessors) { + buffer.push( + //由于ä¸çŸ¥å¯¹æ–¹ä¼šä¼ å…¥ä»€ä¹ˆ,å› æ­¤set, let都用上 + "\tPublic Property Let [" + name + "](val" + expose + ")", //setter + "\t\tCall [__proxy__](Me,[__data__], \"" + name + "\", val" + expose + ")", + "\tEnd Property", + "\tPublic Property Set [" + name + "](val" + expose + ")", //setter + "\t\tCall [__proxy__](Me,[__data__], \"" + name + "\", val" + expose + ")", + "\tEnd Property", + "\tPublic Property Get [" + name + "]", //getter + "\tOn Error Resume Next", //必须优先使用set语å¥,å¦åˆ™å®ƒä¼šè¯¯å°†æ•°ç»„当字符串返回 + "\t\tSet[" + name + "] = [__proxy__](Me,[__data__],\"" + name + "\")", + "\tIf Err.Number <> 0 Then", + "\t\t[" + name + "] = [__proxy__](Me,[__data__],\"" + name + "\")", + "\tEnd If", + "\tOn Error Goto 0", + "\tEnd Property") + + } + + buffer.push("End Class") + var body = buffer.join("\r\n") + var className =VBClassPool[body] + if (!className) { + className = generateID("VBClass") + window.parseVB("Class " + className + body) + window.parseVB([ + "Function " + className + "Factory(a, b)", //创建实例并传入两个关键的å‚æ•° + "\tDim o", + "\tSet o = (New " + className + ")(a, b)", + "\tSet " + className + "Factory = o", + "End Function" + ].join("\r\n")) + VBClassPool[body] = className + } + var ret = window[className + "Factory"](accessors, VBMediator) //å¾—åˆ°å…¶äº§å“ + return ret //å¾—åˆ°å…¶äº§å“ + } + } +} + +/********************************************************************* + * 监控数组(与ms-each, ms-repeaté…åˆä½¿ç”¨ï¼‰ * + **********************************************************************/ + +function arrayFactory(model) { + var array = [] + array.$id = generateID() + array.$model = model //æ•°æ®æ¨¡åž‹ + array.$events = {} + array.$events[subscribers] = [] + array._ = modelFactory({ + length: model.length + }) + array._.$watch("length", function (a, b) { + array.$fire("length", a, b) + }) + for (var i in EventBus) { + array[i] = EventBus[i] + } + avalon.mix(array, arrayPrototype) + return array +} + +function mutateArray(method, pos, n, index, method2, pos2, n2) { + var oldLen = this.length, loop = 2 + while (--loop) { + switch (method) { + case "add": + /* jshint ignore:start */ + var array = this.$model.slice(pos, pos + n).map(function (el) { + if (rcomplexType.test(avalon.type(el))) { + return el.$id ? el : modelFactory(el, 0, el) + } else { + return el + } + }) + /* jshint ignore:end */ + _splice.apply(this, [pos, 0].concat(array)) + this._fire("add", pos, n) + break + case "del": + var ret = this._splice(pos, n) + this._fire("del", pos, n) + break + } + if (method2) { + method = method2 + pos = pos2 + n = n2 + loop = 2 + method2 = 0 + } + } + this._fire("index", index) + if (this.length !== oldLen) { + this._.length = this.length + } + return ret +} + +var _splice = ap.splice +var arrayPrototype = { + _splice: _splice, + _fire: function (method, a, b) { + fireDependencies(this.$events[subscribers], method, a, b) + }, + size: function () { //å–得数组长度,这个函数å¯ä»¥åŒæ­¥è§†å›¾ï¼Œlengthä¸èƒ½ + return this._.length + }, + pushArray: function (array) { + var m = array.length, n = this.length + if (m) { + ap.push.apply(this.$model, array) + mutateArray.call(this, "add", n, m, Math.max(0, n - 1)) + } + return m + n + }, + push: function () { + //http://jsperf.com/closure-with-arguments + var array = [] + var i, n = arguments.length + for (i = 0; i < n; i++) { + array[i] = arguments[i] + } + return this.pushArray(array) + }, + unshift: function () { + var m = arguments.length, n = this.length + if (m) { + ap.unshift.apply(this.$model, arguments) + mutateArray.call(this, "add", 0, m, 0) + } + return m + n //IE67çš„unshiftä¸ä¼šè¿”回长度 + }, + shift: function () { + if (this.length) { + var el = this.$model.shift() + mutateArray.call(this, "del", 0, 1, 0) + return el //返回被移除的元素 + } + }, + pop: function () { + var n = this.length + if (n) { + var el = this.$model.pop() + mutateArray.call(this, "del", n - 1, 1, Math.max(0, n - 2)) + return el //返回被移除的元素 + } + }, + splice: function (start) { + var m = arguments.length, args = [], change + var removed = _splice.apply(this.$model, arguments) + if (removed.length) { //如果用户删掉了元素 + args.push("del", start, removed.length, 0) + change = true + } + if (m > 2) { //如果用户添加了元素 + if (change) { + args.splice(3, 1, 0, "add", start, m - 2) + } else { + args.push("add", start, m - 2, 0) + } + change = true + } + if (change) { //返回被移除的元素 + return mutateArray.apply(this, args) + } else { + return [] + } + }, + contains: function (el) { //判定是å¦åŒ…å« + return this.indexOf(el) !== -1 + }, + remove: function (el) { //移除第一个等于给定值的元素 + return this.removeAt(this.indexOf(el)) + }, + removeAt: function (index) { //移除指定索引上的元素 + if (index >= 0) { + this.$model.splice(index, 1) + return mutateArray.call(this, "del", index, 1, 0) + } + return [] + }, + clear: function () { + this.$model.length = this.length = this._.length = 0 //清空数组 + this._fire("clear", 0) + return this + }, + removeAll: function (all) { //移除N个元素 + if (Array.isArray(all)) { + for (var i = this.length - 1; i >= 0; i--) { + if (all.indexOf(this[i]) !== -1) { + this.removeAt(i) + } + } + } else if (typeof all === "function") { + for ( i = this.length - 1; i >= 0; i--) { + var el = this[i] + if (all(el, i)) { + this.removeAt(i) + } + } + } else { + this.clear() + } + }, + ensure: function (el) { + if (!this.contains(el)) { //åªæœ‰ä¸å­˜åœ¨æ‰push + this.push(el) + } + return this + }, + set: function (index, val) { + if (index >= 0) { + var valueType = avalon.type(val) + if (val && val.$model) { + val = val.$model + } + var target = this[index] + if (valueType === "object") { + for (var i in val) { + if (target.hasOwnProperty(i)) { + target[i] = val[i] + } + } + } else if (valueType === "array") { + target.clear().push.apply(target, val) + } else if (target !== val) { + this[index] = val + this.$model[index] = val + this._fire("set", index, val) + } + } + return this + } +} +//相当于原æ¥bindingExecutors.repeat çš„index分支 +function resetIndex(array, pos) { + var last = array.length - 1 + for (var el; el = array[pos]; pos++) { + el.$index = pos + el.$first = pos === 0 + el.$last = pos === last + } +} + +function sortByIndex(array, indexes) { + var map = {}; + for (var i = 0, n = indexes.length; i < n; i++) { + map[i] = array[i] // preserve + var j = indexes[i] + if (j in map) { + array[i] = map[j] + delete map[j] + } else { + array[i] = array[j] + } + } +} + +"sort,reverse".replace(rword, function (method) { + arrayPrototype[method] = function () { + var newArray = this.$model//这是è¦æŽ’åºçš„新数组 + var oldArray = newArray.concat() //ä¿æŒåŽŸæ¥çŠ¶æ€çš„旧数组 + var mask = Math.random() + var indexes = [] + var hasSort + ap[method].apply(newArray, arguments) //æŽ’åº + for (var i = 0, n = oldArray.length; i < n; i++) { + var neo = newArray[i] + var old = oldArray[i] + if (isEqual(neo, old)) { + indexes.push(i) + } else { + var index = oldArray.indexOf(neo) + indexes.push(index)//得到新数组的æ¯ä¸ªå…ƒç´ åœ¨æ—§æ•°ç»„对应的ä½ç½® + oldArray[index] = mask //å±è”½å·²ç»æ‰¾è¿‡çš„元素 + hasSort = true + } + } + if (hasSort) { + sortByIndex(this, indexes) + // sortByIndex(this.$proxy, indexes) + this._fire("move", indexes) + this._fire("index", 0) + } + return this + } +}) + + +/********************************************************************* + * ä¾èµ–调度系统 * + **********************************************************************/ +//检测两个对象间的ä¾èµ–关系 +var dependencyDetection = (function () { + var outerFrames = [] + var currentFrame + return { + begin: function (accessorObject) { + //accessorObject为一个拥有callback的对象 + outerFrames.push(currentFrame) + currentFrame = accessorObject + }, + end: function () { + currentFrame = outerFrames.pop() + }, + collectDependency: function (vmodel, accessor) { + if (currentFrame) { + //被dependencyDetection.begin调用 + currentFrame.callback(vmodel, accessor); + } + } + }; +})() +//将绑定对象注入到其ä¾èµ–项的订阅数组中 +var ronduplex = /^(duplex|on)$/ +avalon.injectBinding = function (data) { + var valueFn = data.evaluator + if (valueFn) { //如果是求值函数 + dependencyDetection.begin({ + callback: function (vmodel, dependency) { + injectDependency(vmodel.$events[dependency._name], data) + } + }) + try { + var value = ronduplex.test(data.type) ? data : valueFn.apply(0, data.args) + if(value === void 0){ + delete data.evaluator + } + data.handler(value, data.element, data) + } catch (e) { + //log("warning:exception throwed in [avalon.injectBinding] " + e) + delete data.evaluator + var node = data.element + if (node.nodeType === 3) { + var parent = node.parentNode + if (kernel.commentInterpolate) { + parent.replaceChild(DOC.createComment(data.value), node) + } else { + node.data = openTag + (data.oneTime ? "::" : "") + data.value + closeTag + } + } + } finally { + dependencyDetection.end() + } + } +} + +//å°†ä¾èµ–项(比它高层的访问器或构建视图刷新函数的绑定对象)注入到订阅者数组 +function injectDependency(list, data) { + if (data.oneTime) + return + if (list && avalon.Array.ensure(list, data) && data.element) { + injectDisposeQueue(data, list) + } +} + +//通知ä¾èµ–于这个访问器的订阅者更新自身 +function fireDependencies(list) { + if (list && list.length) { + if (new Date() - beginTime > 444 && typeof list[0] === "object") { + rejectDisposeQueue() + } + var args = aslice.call(arguments, 1) + for (var i = list.length, fn; fn = list[--i]; ) { + var el = fn.element + if (el && el.parentNode) { + try { + var valueFn = fn.evaluator + if (fn.$repeat) { + fn.handler.apply(fn, args) //处ç†ç›‘控数组的方法 + }else if("$repeat" in fn || !valueFn ){//如果没有eval,å…ˆeval + bindingHandlers[fn.type](fn, fn.vmodels) + } else if (fn.type !== "on") { //事件绑定åªèƒ½ç”±ç”¨æˆ·è§¦å‘,ä¸èƒ½ç”±ç¨‹åºè§¦å‘ + var value = valueFn.apply(0, fn.args || []) + fn.handler(value, el, fn) + } + } catch (e) { } + } + } + } +} +/********************************************************************* + * 定时GC回收机制 * + **********************************************************************/ +var disposeCount = 0 +var disposeQueue = avalon.$$subscribers = [] +var beginTime = new Date() +var oldInfo = {} +var uuid2Node = {} +function getUid(obj, makeID) { //IE9+,标准æµè§ˆå™¨ + if (!obj.uuid && !makeID) { + obj.uuid = ++disposeCount + uuid2Node[obj.uuid] = obj + } + return obj.uuid +} +function getNode(uuid) { + return uuid2Node[uuid] +} +//添加到回收列队中 +function injectDisposeQueue(data, list) { + var elem = data.element + if (!data.uuid) { + if (elem.nodeType !== 1) { + data.uuid = data.type + (data.pos || 0) + "-" + getUid(elem.parentNode) + } else { + data.uuid = data.name + "-" + getUid(elem) + } + } + var lists = data.lists || (data.lists = []) + avalon.Array.ensure(lists, list) + list.$uuid = list.$uuid || generateID() + if (!disposeQueue[data.uuid]) { + disposeQueue[data.uuid] = 1 + disposeQueue.push(data) + } +} + +function rejectDisposeQueue(data) { + if (avalon.optimize) + return + var i = disposeQueue.length + var n = i + var allTypes = [] + var iffishTypes = {} + var newInfo = {} + //对页é¢ä¸Šæ‰€æœ‰ç»‘定对象进行分门别类, åªæ£€æµ‹ä¸ªæ•°å‘生å˜åŒ–的类型 + while (data = disposeQueue[--i]) { + var type = data.type + if (newInfo[type]) { + newInfo[type]++ + } else { + newInfo[type] = 1 + allTypes.push(type) + } + } + var diff = false + allTypes.forEach(function (type) { + if (oldInfo[type] !== newInfo[type]) { + iffishTypes[type] = 1 + diff = true + } + }) + i = n + if (diff) { + while (data = disposeQueue[--i]) { + if (!data.element) + continue + if (iffishTypes[data.type] && shouldDispose(data.element)) { //如果它没有在DOMæ ‘ + disposeQueue.splice(i, 1) + delete disposeQueue[data.uuid] + delete uuid2Node[data.element.uuid] + var lists = data.lists + for (var k = 0, list; list = lists[k++]; ) { + avalon.Array.remove(lists, list) + avalon.Array.remove(list, data) + } + disposeData(data) + } + } + } + oldInfo = newInfo + beginTime = new Date() +} + +function disposeData(data) { + data.element = null + data.rollback && data.rollback() + for (var key in data) { + data[key] = null + } +} + +function shouldDispose(el) { + try {//IE下,如果文本节点脱离DOM树,访问parentNode会报错 + if (!el.parentNode) { + return true + } + } catch (e) { + return true + } + + return el.msRetain ? 0 : (el.nodeType === 1 ? !root.contains(el) : !avalon.contains(root, el)) +} + +/************************************************************************ + * HTML处ç†(parseHTML, innerHTML, clearHTML) * + ************************************************************************/ +// We have to close these tags to support XHTML +var tagHooks = { + area: [1, "", ""], + param: [1, "", ""], + col: [2, "", "
"], + legend: [1, "
", "
"], + option: [1, ""], + thead: [1, "", "
"], + tr: [2, "", "
"], + td: [3, "", "
"], + g: [1, '', ''], + //IE6-8在用innerHTML生æˆèŠ‚点时,ä¸èƒ½ç›´æŽ¥åˆ›å»ºno-scope元素与HTML5的新标签 + _default: W3C ? [0, "", ""] : [1, "X
", "
"] //divå¯ä»¥ä¸ç”¨é—­åˆ +} +tagHooks.th = tagHooks.td +tagHooks.optgroup = tagHooks.option +tagHooks.tbody = tagHooks.tfoot = tagHooks.colgroup = tagHooks.caption = tagHooks.thead +String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function (tag) { + tagHooks[tag] = tagHooks.g //处ç†SVG +}) +var rtagName = /<([\w:]+)/ //å–å¾—å…¶tagName +var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig +var rcreate = W3C ? /[^\d\D]/ : /(<(?:script|link|style|meta|noscript))/ig +var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"]) +var rnest = /<(?:tb|td|tf|th|tr|col|opt|leg|cap|area)/ //需è¦å¤„ç†å¥—嵌关系的标签 +var script = DOC.createElement("script") +var rhtml = /<|&#?\w+;/ +avalon.parseHTML = function (html) { + var fragment = avalonFragment.cloneNode(false) + if (typeof html !== "string") { + return fragment + } + if (!rhtml.test(html)) { + fragment.appendChild(DOC.createTextNode(html)) + return fragment + } + html = html.replace(rxhtml, "<$1>").trim() + var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(), + //å–得其标签å + wrap = tagHooks[tag] || tagHooks._default, + wrapper = cinerator, + firstChild, neo + if (!W3C) { //fix IE + html = html.replace(rcreate, "
$1") //在link style script等标签之å‰æ·»åŠ ä¸€ä¸ªè¡¥ä¸ + } + wrapper.innerHTML = wrap[1] + html + wrap[2] + var els = wrapper.getElementsByTagName("script") + if (els.length) { //使用innerHTML生æˆçš„script节点ä¸ä¼šå‘出请求与执行text属性 + for (var i = 0, el; el = els[i++]; ) { + if (scriptTypes[el.type]) { + //以å·é¾™è½¬å‡¤æ–¹å¼æ¢å¤æ‰§è¡Œè„šæœ¬åŠŸèƒ½ + neo = script.cloneNode(false) //FFä¸èƒ½çœç•¥å‚æ•° + ap.forEach.call(el.attributes, function (attr) { + if (attr && attr.specified) { + neo[attr.name] = attr.value //å¤åˆ¶å…¶å±žæ€§ + neo.setAttribute(attr.name, attr.value) + } + }) // jshint ignore:line + neo.text = el.text + el.parentNode.replaceChild(neo, el) //替æ¢èŠ‚点 + } + } + } + if (!W3C) { //fix IE + var target = wrap[1] === "X
" ? wrapper.lastChild.firstChild : wrapper.lastChild + if (target && target.tagName === "TABLE" && tag !== "tbody") { + //IE6-7å¤„ç† --> , + // --> , + // -->
+ for (els = target.childNodes, i = 0; el = els[i++]; ) { + if (el.tagName === "TBODY" && !el.innerHTML) { + target.removeChild(el) + break + } + } + } + els = wrapper.getElementsByTagName("br") + var n = els.length + while (el = els[--n]) { + if (el.className === "msNoScope") { + el.parentNode.removeChild(el) + } + } + for (els = wrapper.all, i = 0; el = els[i++]; ) { //fix VML + if (isVML(el)) { + fixVML(el) + } + } + } + //移除我们为了符åˆå¥—嵌关系而添加的标签 + for (i = wrap[0]; i--; wrapper = wrapper.lastChild) { + } + while (firstChild = wrapper.firstChild) { // å°†wrapperä¸Šçš„èŠ‚ç‚¹è½¬ç§»åˆ°æ–‡æ¡£ç¢Žç‰‡ä¸Šï¼ + fragment.appendChild(firstChild) + } + return fragment +} + +function isVML(src) { + var nodeName = src.nodeName + return nodeName.toLowerCase() === nodeName && src.scopeName && src.outerText === "" +} + +function fixVML(node) { + if (node.currentStyle.behavior !== "url(#default#VML)") { + node.style.behavior = "url(#default#VML)" + node.style.display = "inline-block" + node.style.zoom = 1 //hasLayout + } +} +avalon.innerHTML = function (node, html) { + if (!W3C && (!rcreate.test(html) && !rnest.test(html))) { + try { + node.innerHTML = html + return + } catch (e) { + } + } + var a = this.parseHTML(html) + this.clearHTML(node).appendChild(a) +} +avalon.clearHTML = function (node) { + node.textContent = "" + while (node.firstChild) { + node.removeChild(node.firstChild) + } + return node +} + +/********************************************************************* + * avalon的原型方法定义区 * + **********************************************************************/ + +function hyphen(target) { + //转æ¢ä¸ºè¿žå­—符线风格 + return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase() +} + +function camelize(target) { + //æå‰åˆ¤æ–­ï¼Œæ高getStyle等的效率 + if (!target || target.indexOf("-") < 0 && target.indexOf("_") < 0) { + return target + } + //转æ¢ä¸ºé©¼å³°é£Žæ ¼ + return target.replace(/[-_][^-_]/g, function(match) { + return match.charAt(1).toUpperCase() + }) +} + +var fakeClassListMethods = { + _toString: function() { + var node = this.node + var cls = node.className + var str = typeof cls === "string" ? cls : cls.baseVal + return str.split(/\s+/).join(" ") + }, + _contains: function(cls) { + return (" " + this + " ").indexOf(" " + cls + " ") > -1 + }, + _add: function(cls) { + if (!this.contains(cls)) { + this._set(this + " " + cls) + } + }, + _remove: function(cls) { + this._set((" " + this + " ").replace(" " + cls + " ", " ")) + }, + __set: function(cls) { + cls = cls.trim() + var node = this.node + if (rsvg.test(node)) { + //SVG元素的className是一个对象 SVGAnimatedString { baseVal="", animVal=""},åªèƒ½é€šè¿‡set/getAttributeæ“作 + node.setAttribute("class", cls) + } else { + node.className = cls + } + } //toggle存在版本差异,因此ä¸ä½¿ç”¨å®ƒ +} + + function fakeClassList(node) { + if (!("classList" in node)) { + node.classList = { + node: node + } + for (var k in fakeClassListMethods) { + node.classList[k.slice(1)] = fakeClassListMethods[k] + } + } + return node.classList + } + + + "add,remove".replace(rword, function(method) { + avalon.fn[method + "Class"] = function(cls) { + var el = this[0] + //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26 + if (cls && typeof cls === "string" && el && el.nodeType === 1) { + cls.replace(/\S+/g, function(c) { + fakeClassList(el)[method](c) + }) + } + return this + } + }) + avalon.fn.mix({ + hasClass: function(cls) { + var el = this[0] || {} + return el.nodeType === 1 && fakeClassList(el).contains(cls) + }, + toggleClass: function(value, stateVal) { + var className, i = 0 + var classNames = String(value).split(/\s+/) + var isBool = typeof stateVal === "boolean" + while ((className = classNames[i++])) { + var state = isBool ? stateVal : !this.hasClass(className) + this[state ? "addClass" : "removeClass"](className) + } + return this + }, + attr: function(name, value) { + if (arguments.length === 2) { + this[0].setAttribute(name, value) + return this + } else { + return this[0].getAttribute(name) + } + }, + data: function(name, value) { + name = "data-" + hyphen(name || "") + switch (arguments.length) { + case 2: + this.attr(name, value) + return this + case 1: + var val = this.attr(name) + return parseData(val) + case 0: + var ret = {} + ap.forEach.call(this[0].attributes, function(attr) { + if (attr) { + name = attr.name + if (!name.indexOf("data-")) { + name = camelize(name.slice(5)) + ret[name] = parseData(attr.value) + } + } + }) + return ret + } + }, + removeData: function(name) { + name = "data-" + hyphen(name) + this[0].removeAttribute(name) + return this + }, + css: function(name, value) { + if (avalon.isPlainObject(name)) { + for (var i in name) { + avalon.css(this, i, name[i]) + } + } else { + var ret = avalon.css(this, name, value) + } + return ret !== void 0 ? ret : this + }, + position: function() { + var offsetParent, offset, + elem = this[0], + parentOffset = { + top: 0, + left: 0 + } + if (!elem) { + return + } + if (this.css("position") === "fixed") { + offset = elem.getBoundingClientRect() + } else { + offsetParent = this.offsetParent() //得到真正的offsetParent + offset = this.offset() // 得到正确的offsetParent + if (offsetParent[0].tagName !== "HTML") { + parentOffset = offsetParent.offset() + } + parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true) + parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true) + + // Subtract offsetParent scroll positions + parentOffset.top -= offsetParent.scrollTop() + parentOffset.left -= offsetParent.scrollLeft() + } + return { + top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true), + left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true) + } + }, + offsetParent: function() { + var offsetParent = this[0].offsetParent + while (offsetParent && avalon.css(offsetParent, "position") === "static") { + offsetParent = offsetParent.offsetParent; + } + return avalon(offsetParent || root) + }, + bind: function(type, fn, phase) { + if (this[0]) { //此方法ä¸ä¼šé“¾ + return avalon.bind(this[0], type, fn, phase) + } + }, + unbind: function(type, fn, phase) { + if (this[0]) { + avalon.unbind(this[0], type, fn, phase) + } + return this + }, + val: function(value) { + var node = this[0] + if (node && node.nodeType === 1) { + var get = arguments.length === 0 + var access = get ? ":get" : ":set" + var fn = valHooks[getValType(node) + access] + if (fn) { + var val = fn(node, value) + } else if (get) { + return (node.value || "").replace(/\r/g, "") + } else { + node.value = value + } + } + return get ? val : this + } + }) + + function parseData(data) { + try { + if (typeof data === "object") + return data + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? avalon.parseJSON(data) : data + } catch (e) {} + return data + } +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g +avalon.parseJSON = window.JSON ? JSON.parse : function(data) { + if (typeof data === "string") { + data = data.trim(); + if (data) { + if (rvalidchars.test(data.replace(rvalidescape, "@") + .replace(rvalidtokens, "]") + .replace(rvalidbraces, ""))) { + return (new Function("return " + data))() // jshint ignore:line + } + } + avalon.error("Invalid JSON: " + data) + } + return data +} + +//生æˆavalon.fn.scrollLeft, avalon.fn.scrollTop方法 +avalon.each({ + scrollLeft: "pageXOffset", + scrollTop: "pageYOffset" +}, function(method, prop) { + avalon.fn[method] = function(val) { + var node = this[0] || {}, win = getWindow(node), + top = method === "scrollTop" + if (!arguments.length) { + return win ? (prop in win) ? win[prop] : root[method] : node[method] + } else { + if (win) { + win.scrollTo(!top ? val : avalon(win).scrollLeft(), top ? val : avalon(win).scrollTop()) + } else { + node[method] = val + } + } + } +}) + +function getWindow(node) { + return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView || node.parentWindow : false; +} +//=============================css相关======================= +var cssHooks = avalon.cssHooks = {} +var prefixes = ["", "-webkit-", "-o-", "-moz-", "-ms-"] +var cssMap = { + "float": W3C ? "cssFloat" : "styleFloat" +} +avalon.cssNumber = oneObject("columnCount,order,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom") + +avalon.cssName = function(name, host, camelCase) { + if (cssMap[name]) { + return cssMap[name] + } + host = host || root.style + for (var i = 0, n = prefixes.length; i < n; i++) { + camelCase = camelize(prefixes[i] + name) + if (camelCase in host) { + return (cssMap[name] = camelCase) + } + } + return null +} +cssHooks["@:set"] = function(node, name, value) { + try { //node.style.width = NaN;node.style.width = "xxxxxxx";node.style.width = undefine 在旧å¼IE下会抛异常 + node.style[name] = value + } catch (e) {} +} +if (window.getComputedStyle) { + cssHooks["@:get"] = function(node, name) { + if (!node || !node.style) { + throw new Error("getComputedStyleè¦æ±‚传入一个节点 " + node) + } + var ret, styles = getComputedStyle(node, null) + if (styles) { + ret = name === "filter" ? styles.getPropertyValue(name) : styles[name] + if (ret === "") { + ret = node.style[name] //其他æµè§ˆå™¨éœ€è¦æˆ‘们手动å–内è”æ ·å¼ + } + } + return ret + } + cssHooks["opacity:get"] = function(node) { + var ret = cssHooks["@:get"](node, "opacity") + return ret === "" ? "1" : ret + } +} else { + var rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i + var rposition = /^(top|right|bottom|left)$/ + var ralpha = /alpha\([^)]*\)/i + var ie8 = !! window.XDomainRequest + var salpha = "DXImageTransform.Microsoft.Alpha" + var border = { + thin: ie8 ? '1px' : '2px', + medium: ie8 ? '3px' : '4px', + thick: ie8 ? '5px' : '6px' + } + cssHooks["@:get"] = function(node, name) { + //å–得精确值,ä¸è¿‡å®ƒæœ‰å¯èƒ½æ˜¯å¸¦em,pc,mm,pt,%ç­‰å•ä½ + var currentStyle = node.currentStyle + var ret = currentStyle[name] + if ((rnumnonpx.test(ret) && !rposition.test(ret))) { + //①,ä¿å­˜åŽŸæœ‰çš„style.left, runtimeStyle.left, + var style = node.style, + left = style.left, + rsLeft = node.runtimeStyle.left + //②由于③处的style.left = xxx会影å“到currentStyle.left, + //因此把它currentStyle.left放到runtimeStyle.left, + //runtimeStyle.left拥有最高优先级,ä¸ä¼šstyle.leftå½±å“ + node.runtimeStyle.left = currentStyle.left + //③将精确值赋给到style.left,然åŽé€šè¿‡IEçš„å¦ä¸€ä¸ªç§æœ‰å±žæ€§ style.pixelLeft + //得到å•ä½ä¸ºpx的结果;fontSize的分支è§http://bugs.jquery.com/ticket/760 + style.left = name === 'fontSize' ? '1em' : (ret || 0) + ret = style.pixelLeft + "px" + //④还原 style.left,runtimeStyle.left + style.left = left + node.runtimeStyle.left = rsLeft + } + if (ret === "medium") { + name = name.replace("Width", "Style") + //border width 默认值为medium,å³ä½¿å…¶ä¸º0" + if (currentStyle[name] === "none") { + ret = "0px" + } + } + return ret === "" ? "auto" : border[ret] || ret + } + cssHooks["opacity:set"] = function(node, name, value) { + var style = node.style + var opacity = isFinite(value) && value <= 1 ? "alpha(opacity=" + value * 100 + ")" : "" + var filter = style.filter || ""; + style.zoom = 1 + //ä¸èƒ½ä½¿ç”¨ä»¥ä¸‹æ–¹å¼è®¾ç½®é€æ˜Žåº¦ + //node.filters.alpha.opacity = value * 100 + style.filter = (ralpha.test(filter) ? + filter.replace(ralpha, opacity) : + filter + " " + opacity).trim() + if (!style.filter) { + style.removeAttribute("filter") + } + } + cssHooks["opacity:get"] = function(node) { + //这是最快的获å–IEé€æ˜Žå€¼çš„æ–¹å¼ï¼Œä¸éœ€è¦åŠ¨ç”¨æ­£åˆ™äº†ï¼ + var alpha = node.filters.alpha || node.filters[salpha], + op = alpha && alpha.enabled ? alpha.opacity : 100 + return (op / 100) + "" //ç¡®ä¿è¿”回的是字符串 + } +} + +"top,left".replace(rword, function(name) { + cssHooks[name + ":get"] = function(node) { + var computed = cssHooks["@:get"](node, name) + return /px$/.test(computed) ? computed : + avalon(node).position()[name] + "px" + } +}) + +var cssShow = { + position: "absolute", + visibility: "hidden", + display: "block" +} + +var rdisplayswap = /^(none|table(?!-c[ea]).+)/ + + function showHidden(node, array) { + //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html + if (node.offsetWidth <= 0) { //opera.offsetWidthå¯èƒ½å°äºŽ0 + if (rdisplayswap.test(cssHooks["@:get"](node, "display"))) { + var obj = { + node: node + } + for (var name in cssShow) { + obj[name] = node.style[name] + node.style[name] = cssShow[name] + } + array.push(obj) + } + var parent = node.parentNode + if (parent && parent.nodeType === 1) { + showHidden(parent, array) + } + } + } + "Width,Height".replace(rword, function(name) { //fix 481 + var method = name.toLowerCase(), + clientProp = "client" + name, + scrollProp = "scroll" + name, + offsetProp = "offset" + name + cssHooks[method + ":get"] = function(node, which, override) { + var boxSizing = -4 + if (typeof override === "number") { + boxSizing = override + } + which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"] + var ret = node[offsetProp] // border-box 0 + if (boxSizing === 2) { // margin-box 2 + return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true) + } + if (boxSizing < 0) { // padding-box -2 + ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true) + } + if (boxSizing === -4) { // content-box -4 + ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true) + } + return ret + } + cssHooks[method + "&get"] = function(node) { + var hidden = []; + showHidden(node, hidden); + var val = cssHooks[method + ":get"](node) + for (var i = 0, obj; obj = hidden[i++];) { + node = obj.node + for (var n in obj) { + if (typeof obj[n] === "string") { + node.style[n] = obj[n] + } + } + } + return val; + } + avalon.fn[method] = function(value) { //会忽视其display + var node = this[0] + if (arguments.length === 0) { + if (node.setTimeout) { //å–得窗å£å°ºå¯¸,IE9åŽå¯ä»¥ç”¨node.innerWidth /innerHeight代替 + return node["inner" + name] || node.document.documentElement[clientProp] + } + if (node.nodeType === 9) { //å–得页é¢å°ºå¯¸ + var doc = node.documentElement + //FF chrome html.scrollHeight< body.scrollHeight + //IE æ ‡å‡†æ¨¡å¼ : html.scrollHeight> body.scrollHeight + //IE æ€ªå¼‚æ¨¡å¼ : html.scrollHeight 最大等于å¯è§†çª—å£å¤šä¸€ç‚¹ï¼Ÿ + return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp]) + } + return cssHooks[method + "&get"](node) + } else { + return this.css(method, value) + } + } + avalon.fn["inner" + name] = function() { + return cssHooks[method + ":get"](this[0], void 0, -2) + } + avalon.fn["outer" + name] = function(includeMargin) { + return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0) + } + }) + avalon.fn.offset = function() { //å–å¾—è·ç¦»é¡µé¢å·¦å³è§’çš„åæ ‡ + var node = this[0], + box = { + left: 0, + top: 0 + } + if (!node || !node.tagName || !node.ownerDocument) { + return box + } + var doc = node.ownerDocument, + body = doc.body, + root = doc.documentElement, + win = doc.defaultView || doc.parentWindow + if (!avalon.contains(root, node)) { + return box + } + //http://hkom.blog1.fc2.com/?mode=m&no=750 bodyçš„å移é‡æ˜¯ä¸åŒ…å«marginçš„ + //我们å¯ä»¥é€šè¿‡getBoundingClientRectæ¥èŽ·å¾—元素相对于clientçš„rect. + //http://msdn.microsoft.com/en-us/library/ms536433.aspx + if (node.getBoundingClientRect) { + box = node.getBoundingClientRect() // BlackBerry 5, iOS 3 (original iPhone) + } + //chrome/IE6: body.scrollTop, firefox/other: root.scrollTop + var clientTop = root.clientTop || body.clientTop, + clientLeft = root.clientLeft || body.clientLeft, + scrollTop = Math.max(win.pageYOffset || 0, root.scrollTop, body.scrollTop), + scrollLeft = Math.max(win.pageXOffset || 0, root.scrollLeft, body.scrollLeft) + // 把滚动è·ç¦»åŠ åˆ°left,top中去。 + // IE一些版本中会自动为HTML元素加上2pxçš„border,我们需è¦åŽ»æŽ‰å®ƒ + // http://msdn.microsoft.com/en-us/library/ms533564(VS.85).aspx + return { + top: box.top + scrollTop - clientTop, + left: box.left + scrollLeft - clientLeft + } + } + + //==================================val相关============================ + + function getValType(elem) { + var ret = elem.tagName.toLowerCase() + return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret + } +var roption = /^]+))?)*\s+value[\s=]/i +var valHooks = { + "option:get": IEVersion ? function(node) { + //在IE11åŠW3C,如果没有指定value,那么node.value默认为node.text(存在trim作),但IE9-10则是å–innerHTML(没trimæ“作) + //specified并ä¸å¯é ï¼Œå› æ­¤é€šè¿‡åˆ†æžouterHTML判定用户有没有显示定义value + return roption.test(node.outerHTML) ? node.value : node.text.trim() + } : function(node) { + return node.value + }, + "select:get": function(node, value) { + var option, options = node.options, + index = node.selectedIndex, + getter = valHooks["option:get"], + one = node.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? max : one ? index : 0 + for (; i < max; i++) { + option = options[i] + //æ—§å¼IE在resetåŽä¸ä¼šæ”¹å˜selected,需è¦æ”¹ç”¨i === index判定 + //我们过滤所有disabledçš„option元素,但在safari5下,如果设置select为disable,那么其所有孩å­éƒ½disable + //因此当一个元素为disable,需è¦æ£€æµ‹å…¶æ˜¯å¦æ˜¾å¼è®¾ç½®äº†disableåŠå…¶çˆ¶èŠ‚点的disable情况 + if ((option.selected || i === index) && !option.disabled) { + value = getter(option) + if (one) { + return value + } + //收集所有selected值组æˆæ•°ç»„返回 + values.push(value) + } + } + return values + }, + "select:set": function(node, values, optionSet) { + values = [].concat(values) //强制转æ¢ä¸ºæ•°ç»„ + var getter = valHooks["option:get"] + for (var i = 0, el; el = node.options[i++];) { + if ((el.selected = values.indexOf(getter(el)) > -1)) { + optionSet = true + } + } + if (!optionSet) { + node.selectedIndex = -1 + } + } +} + +/********************************************************************* + * 编译系统 * + **********************************************************************/ +var meta = { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"': '\\"', + '\\': '\\\\' +} +var quote = window.JSON && JSON.stringify || function(str) { + return '"' + str.replace(/[\\\"\x00-\x1f]/g, function(a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' +} + +var keywords = [ + "break,case,catch,continue,debugger,default,delete,do,else,false", + "finally,for,function,if,in,instanceof,new,null,return,switch,this", + "throw,true,try,typeof,var,void,while,with", /* 关键字*/ + "abstract,boolean,byte,char,class,const,double,enum,export,extends", + "final,float,goto,implements,import,int,interface,long,native", + "package,private,protected,public,short,static,super,synchronized", + "throws,transient,volatile", /*ä¿ç•™å­—*/ + "arguments,let,yield,undefined" /* ECMA 5 - use strict*/].join(",") +var rrexpstr = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g +var rsplit = /[^\w$]+/g +var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g') +var rnumber = /\b\d[^,]*/g +var rcomma = /^,+|,+$/g +var variablePool = new Cache(512) +var getVariables = function (code) { + var key = "," + code.trim() + var ret = variablePool.get(key) + if (ret) { + return ret + } + var match = code + .replace(rrexpstr, "") + .replace(rsplit, ",") + .replace(rkeywords, "") + .replace(rnumber, "") + .replace(rcomma, "") + .split(/^$|,+/) + return variablePool.put(key, uniqSet(match)) +} +/*添加赋值语å¥*/ + +function addAssign(vars, scope, name, data) { + var ret = [], + prefix = " = " + name + "." + for (var i = vars.length, prop; prop = vars[--i]; ) { + if (scope.hasOwnProperty(prop)) { + ret.push(prop + prefix + prop) + data.vars.push(prop) + if (data.type === "duplex") { + vars.get = name + "." + prop + } + vars.splice(i, 1) + } + } + return ret +} + +function uniqSet(array) { + var ret = [], + unique = {} + for (var i = 0; i < array.length; i++) { + var el = array[i] + var id = el && typeof el.$id === "string" ? el.$id : el + if (!unique[id]) { + unique[id] = ret.push(el) + } + } + return ret +} +//缓存求值函数,以便多次利用 +var evaluatorPool = new Cache(128) +//å–得求值函数åŠå…¶ä¼ å‚ +var rduplex = /\w\[.*\]|\w\.\w/ +var rproxy = /(\$proxy\$[a-z]+)\d+$/ +var rthimRightParentheses = /\)\s*$/ +var rthimOtherParentheses = /\)\s*\|/g +var rquoteFilterName = /\|\s*([$\w]+)/g +var rpatchBracket = /"\s*\["/g +var rthimLeftParentheses = /"\s*\(/g +function parseFilter(val, filters) { + filters = filters + .replace(rthimRightParentheses, "")//处ç†æœ€åŽçš„å°æ‹¬å· + .replace(rthimOtherParentheses, function () {//处ç†å…¶ä»–å°æ‹¬å· + return "],|" + }) + .replace(rquoteFilterName, function (a, b) { //处ç†|åŠå®ƒåŽé¢çš„过滤器的åå­— + return "[" + quote(b) + }) + .replace(rpatchBracket, function () { + return '"],["' + }) + .replace(rthimLeftParentheses, function () { + return '",' + }) + "]" + return "return avalon.filters.$filter(" + val + ", " + filters + ")" +} + +function parseExpr(code, scopes, data) { + var dataType = data.type + var filters = data.filters || "" + var exprId = scopes.map(function (el) { + return String(el.$id).replace(rproxy, "$1") + }) + code + dataType + filters + var vars = getVariables(code).concat(), + assigns = [], + names = [], + args = [], + prefix = "" + //args 是一个对象数组, names 是将è¦ç”Ÿæˆçš„求值函数的å‚æ•° + scopes = uniqSet(scopes) + data.vars = [] + for (var i = 0, sn = scopes.length; i < sn; i++) { + if (vars.length) { + var name = "vm" + expose + "_" + i + names.push(name) + args.push(scopes[i]) + assigns.push.apply(assigns, addAssign(vars, scopes[i], name, data)) + } + } + if (!assigns.length && dataType === "duplex") { + return + } + if (dataType !== "duplex" && (code.indexOf("||") > -1 || code.indexOf("&&") > -1)) { + //https://github.com/RubyLouvre/avalon/issues/583 + data.vars.forEach(function (v) { + var reg = new RegExp("\\b" + v + "(?:\\.\\w+|\\[\\w+\\])+", "ig") + code = code.replace(reg, function (_) { + var c = _.charAt(v.length) + var r = IEVersion ? code.slice(arguments[1] + _.length) : RegExp.rightContext + var method = /^\s*\(/.test(r) + if (c === "." || c === "[" || method) {//比如v为aa,我们åªåŒ¹é…aa.bb,aa[cc],ä¸åŒ¹é…aaa.xxx + var name = "var" + String(Math.random()).replace(/^0\./, "") + if (method) {//array.size() + var array = _.split(".") + if (array.length > 2) { + var last = array.pop() + assigns.push(name + " = " + array.join(".")) + return name + "." + last + } else { + return _ + } + } + assigns.push(name + " = " + _) + return name + } else { + return _ + } + }) + }) + } + //---------------args---------------- + data.args = args + //---------------cache---------------- + delete data.vars + var fn = evaluatorPool.get(exprId) //直接从缓存,å…å¾—é‡å¤ç”Ÿæˆ + if (fn) { + data.evaluator = fn + return + } + prefix = assigns.join(", ") + if (prefix) { + prefix = "var " + prefix + } + if (/\S/.test(filters)) { //文本绑定,åŒå·¥ç»‘定æ‰æœ‰è¿‡æ»¤å™¨ + if (!/text|html/.test(data.type)) { + throw Error("ms-" + data.type + "ä¸æ”¯æŒè¿‡æ»¤å™¨") + } + code = "\nvar ret" + expose + " = " + code + ";\r\n" + code += parseFilter("ret" + expose, filters) + } else if (dataType === "duplex") { //åŒå·¥ç»‘定 + var _body = "'use strict';\nreturn function(vvv){\n\t" + + prefix + + ";\n\tif(!arguments.length){\n\t\treturn " + + code + + "\n\t}\n\t" + (!rduplex.test(code) ? vars.get : code) + + "= vvv;\n} " + try { + fn = Function.apply(noop, names.concat(_body)) + data.evaluator = evaluatorPool.put(exprId, fn) + } catch (e) { + log("debug: parse error," + e.message) + } + return + } else if (dataType === "on") { //事件绑定 + if (code.indexOf("(") === -1) { + code += ".call(this, $event)" + } else { + code = code.replace("(", ".call(this,") + } + names.push("$event") + code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需è¦Function("return ;") + var lastIndex = code.lastIndexOf("\nreturn") + var header = code.slice(0, lastIndex) + var footer = code.slice(lastIndex) + code = header + "\n" + footer + } else { //其他绑定 + code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需è¦Function("return ;") + } + try { + fn = Function.apply(noop, names.concat("'use strict';\n" + prefix + code)) + data.evaluator = evaluatorPool.put(exprId, fn) + } catch (e) { + log("debug: parse error," + e.message) + } finally { + vars = assigns = names = null //释放内存 + } +} + + +//parseExprçš„æ™ºèƒ½å¼•ç”¨ä»£ç† + +function parseExprProxy(code, scopes, data, tokens, noRegister) { + if (Array.isArray(tokens)) { + code = tokens.map(function (el) { + return el.expr ? "(" + el.value + ")" : quote(el.value) + }).join(" + ") + } + parseExpr(code, scopes, data) + if (data.evaluator && !noRegister) { + data.handler = bindingExecutors[data.handlerName || data.type] + //方便调试 + //这里éžå¸¸é‡è¦,我们通过判定视图刷新函数的element是å¦åœ¨DOM树决定 + //将它移出订阅者列表 + avalon.injectBinding(data) + } +} +avalon.parseExprProxy = parseExprProxy +/********************************************************************* + * 扫æ系统 * + **********************************************************************/ + +avalon.scan = function(elem, vmodel) { + elem = elem || root + var vmodels = vmodel ? [].concat(vmodel) : [] + scanTag(elem, vmodels) +} + +//http://www.w3.org/TR/html5/syntax.html#void-elements +var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase()) + +function checkScan(elem, callback, innerHTML) { + var id = setTimeout(function() { + var currHTML = elem.innerHTML + clearTimeout(id) + if (currHTML === innerHTML) { + callback() + } else { + checkScan(elem, callback, currHTML) + } + }) +} + + +function createSignalTower(elem, vmodel) { + var id = elem.getAttribute("avalonctrl") || vmodel.$id + elem.setAttribute("avalonctrl", id) + vmodel.$events.expr = elem.tagName + '[avalonctrl="' + id + '"]' +} + +var getBindingCallback = function(elem, name, vmodels) { + var callback = elem.getAttribute(name) + if (callback) { + for (var i = 0, vm; vm = vmodels[i++]; ) { + if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") { + return vm[callback] + } + } + } +} + +function executeBindings(bindings, vmodels) { + for (var i = 0, data; data = bindings[i++]; ) { + data.vmodels = vmodels + bindingHandlers[data.type](data, vmodels) + if (data.evaluator && data.element && data.element.nodeType === 1) { //移除数æ®ç»‘å®šï¼Œé˜²æ­¢è¢«äºŒæ¬¡è§£æž + //chrome使用removeAttributeNode移除ä¸å­˜åœ¨çš„特性节点时会报错 https://github.com/RubyLouvre/avalon/issues/99 + data.element.removeAttribute(data.name) + } + } + bindings.length = 0 +} + +//https://github.com/RubyLouvre/avalon/issues/636 +var mergeTextNodes = IEVersion && window.MutationObserver ? function (elem) { + var node = elem.firstChild, text + while (node) { + var aaa = node.nextSibling + if (node.nodeType === 3) { + if (text) { + text.nodeValue += node.nodeValue + elem.removeChild(node) + } else { + text = node + } + } else { + text = null + } + node = aaa + } +} : 0 +var roneTime = /^\s*::/ +var rmsAttr = /ms-(\w+)-?(.*)/ +var priorityMap = { + "if": 10, + "repeat": 90, + "data": 100, + "widget": 110, + "each": 1400, + "with": 1500, + "duplex": 2000, + "on": 3000 +} + +var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit") +var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled") +function bindingSorter(a, b) { + return a.priority - b.priority +} + +function scanAttr(elem, vmodels, match) { + var scanNode = true + if (vmodels.length) { + var attributes = getAttributes ? getAttributes(elem) : elem.attributes + var bindings = [] + var fixAttrs = [] + var msData = {} + for (var i = 0, attr; attr = attributes[i++]; ) { + if (attr.specified) { + if (match = attr.name.match(rmsAttr)) { + //如果是以指定å‰ç¼€å‘½åçš„ + var type = match[1] + var param = match[2] || "" + var value = attr.value + var name = attr.name + if (events[type]) { + param = type + type = "on" + } else if (obsoleteAttrs[type]) { + if (type === "enabled") {//åƒæŽ‰ms-enabled绑定,用ms-disabled代替 + log("warning!ms-enabled或ms-attr-enabledå·²ç»è¢«åºŸå¼ƒ") + type = "disabled" + value = "!(" + value + ")" + } + param = type + type = "attr" + name = "ms-" + type + "-"+ param + fixAttrs.push([attr.name, name, value]) + } + msData[name] = value + if (typeof bindingHandlers[type] === "function") { + var newValue = value.replace(roneTime, "") + var oneTime = value !== newValue + var binding = { + type: type, + param: param, + element: elem, + name: name, + value: newValue, + oneTime: oneTime, + uuid: name+"-"+getUid(elem), + //chrome与firefox下Number(param)得到的值ä¸ä¸€æ · #855 + priority: (priorityMap[type] || type.charCodeAt(0) * 10 )+ (Number(param.replace(/\D/g, "")) || 0) + } + if (type === "html" || type === "text") { + var token = getToken(value) + avalon.mix(binding, token) + binding.filters = binding.filters.replace(rhasHtml, function () { + binding.type = "html" + binding.group = 1 + return "" + })// jshint ignore:line + } else if (type === "duplex") { + var hasDuplex = name + } else if (name === "ms-if-loop") { + binding.priority += 100 + } + bindings.push(binding) + if (type === "widget") { + elem.msData = elem.msData || msData + } + } + } + } + } + if (bindings.length) { + bindings.sort(bindingSorter) + fixAttrs.forEach(function (arr) { + log("warning!请改用" + arr[1] + "代替" + arr[0] + "!") + elem.removeAttribute(arr[0]) + elem.setAttribute(arr[1], arr[2]) + }) + //http://bugs.jquery.com/ticket/7071 + //在IE下对VML读å–type属性,会让此元素所有属性都å˜æˆ + if (hasDuplex) { + if (msData["ms-attr-checked"]) { + log("warning!一个控件ä¸èƒ½åŒæ—¶å®šä¹‰ms-attr-checked与" + hasDuplex) + } + if (msData["ms-attr-value"]) { + log("warning!一个控件ä¸èƒ½åŒæ—¶å®šä¹‰ms-attr-value与" + hasDuplex) + } + } + for (i = 0; binding = bindings[i]; i++) { + type = binding.type + if (rnoscanAttrBinding.test(type)) { + return executeBindings(bindings.slice(0, i + 1), vmodels) + } else if (scanNode) { + scanNode = !rnoscanNodeBinding.test(type) + } + } + executeBindings(bindings, vmodels) + } + } + if (scanNode && !stopScan[elem.tagName] && rbind.test(elem.innerHTML.replace(rlt, "<").replace(rgt, ">"))) { + mergeTextNodes && mergeTextNodes(elem) + scanNodeList(elem, vmodels) //扫æå­å­™å…ƒç´  + } +} +var rnoscanAttrBinding = /^if|widget|repeat$/ +var rnoscanNodeBinding = /^each|with|html|include$/ +//IE67下,在循环绑定中,一个节点如果是通过cloneNode得到,自定义属性的specified为false,无法进入里é¢çš„分支, +//但如果我们去掉scanAttr中的attr.specified检测,一个元素会有80+个特性节点(因为它ä¸åŒºåˆ†å›ºæœ‰å±žæ€§ä¸Žè‡ªå®šä¹‰å±žæ€§ï¼‰ï¼Œå¾ˆå®¹æ˜“å¡æ­»é¡µé¢ +if (!"1" [0]) { + var attrPool = new Cache(512) + var rattrs = /\s+(ms-[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g, + rquote = /^['"]/, + rtag = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/i, + ramp = /&/g + //IE6-8解æžHTML5新标签,会将它分解两个元素节点与一个文本节点 + //
ddd
+ // window.onload = function() { + // var body = document.body + // for (var i = 0, el; el = body.children[i++]; ) { + // avalon.log(el.outerHTML) + // } + // } + //ä¾æ¬¡è¾“出
,
+ var getAttributes = function (elem) { + var html = elem.outerHTML + //处ç†IE6-8解æžHTML5新标签的情况,åŠ
ç­‰åŠé—­åˆæ ‡ç­¾outerHTML为空的情况 + if (html.slice(0, 2) === " ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100) + //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)åž«åŽ + var a = elem.getAttribute("ms-skip") + //#360 在旧å¼IE中 Object标签在引入Flash等资æºæ—¶,å¯èƒ½å‡ºçŽ°æ²¡æœ‰getAttributeNode,innerHTML的情形 + if (!elem.getAttributeNode) { + return log("warning " + elem.tagName + " no getAttributeNode method") + } + var b = elem.getAttributeNode("ms-important") + var c = elem.getAttributeNode("ms-controller") + if (typeof a === "string") { + return + } else if (node = b || c) { + var newVmodel = avalon.vmodels[node.value] + if (!newVmodel) { + return + } + //ms-importantä¸åŒ…å«çˆ¶VM,ms-controller相å + vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels) + var name = node.name + elem.removeAttribute(name) //removeAttributeNodeä¸ä¼šåˆ·æ–°[ms-controller]æ ·å¼è§„则 + avalon(elem).removeClass(name) + createSignalTower(elem, newVmodel) + } + scanAttr(elem, vmodels) //扫æ特性节点 +} +var rhasHtml = /\|\s*html(?:\b|$)/, + r11a = /\|\|/g, + rlt = /</g, + rgt = />/g, + rstringLiteral = /(['"])(\\\1|.)+?\1/g +function getToken(value) { + if (value.indexOf("|") > 0) { + var scapegoat = value.replace(rstringLiteral, function (_) { + return Array(_.length + 1).join("1")// jshint ignore:line + }) + var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或 + if (index > -1) { + return { + filters: value.slice(index), + value: value.slice(0, index), + expr: true + } + } + } + return { + value: value, + filters: "", + expr: true + } +} + +function scanExpr(str) { + var tokens = [], + value, start = 0, + stop + do { + stop = str.indexOf(openTag, start) + if (stop === -1) { + break + } + value = str.slice(start, stop) + if (value) { // {{ 左边的文本 + tokens.push({ + value: value, + filters: "", + expr: false + }) + } + start = stop + openTag.length + stop = str.indexOf(closeTag, start) + if (stop === -1) { + break + } + value = str.slice(start, stop) + if (value) { //处ç†{{ }}æ’å€¼è¡¨è¾¾å¼ + tokens.push(getToken(value, start)) + } + start = stop + closeTag.length + } while (1) + value = str.slice(start) + if (value) { //}} å³è¾¹çš„文本 + tokens.push({ + value: value, + expr: false, + filters: "" + }) + } + return tokens +} + +function scanText(textNode, vmodels, index) { + var bindings = [] + tokens = scanExpr(textNode.data) + if (tokens.length) { + for (var i = 0; token = tokens[i++]; ) { + var node = DOC.createTextNode(token.value) //将文本转æ¢ä¸ºæ–‡æœ¬èŠ‚点,并替æ¢åŽŸæ¥çš„文本节点 + if (token.expr) { + token.value = token.value.replace(roneTime, function () { + token.oneTime = true + return "" + }) + token.type = "text" + token.element = node + token.filters = token.filters.replace(rhasHtml, function (a, b,c) { + token.type = "html" + return "" + })// jshint ignore:line + token.pos = index * 1000 + i + bindings.push(token) //收集带有æ’值表达å¼çš„文本 + } + avalonFragment.appendChild(node) + } + textNode.parentNode.replaceChild(avalonFragment, textNode) + if (bindings.length) + executeBindings(bindings, vmodels) + } +} + +var bools = ["autofocus,autoplay,async,allowTransparency,checked,controls", + "declare,disabled,defer,defaultChecked,defaultSelected", + "contentEditable,isMap,loop,multiple,noHref,noResize,noShade", + "open,readOnly,selected" +].join(",") +var boolMap = {} +bools.replace(rword, function(name) { + boolMap[name.toLowerCase()] = name +}) + +var propMap = { //属性å映射 + "accept-charset": "acceptCharset", + "char": "ch", + "charoff": "chOff", + "class": "className", + "for": "htmlFor", + "http-equiv": "httpEquiv" +} + +var anomaly = ["accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan", + "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight", + "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign" +].join(",") +anomaly.replace(rword, function(name) { + propMap[name.toLowerCase()] = name +}) + +var rnoscripts = /(?:[\s\S]+?)<\/noscript>/img +var rnoscriptText = /([\s\S]+?)<\/noscript>/im + +var getXHR = function() { + return new(window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP") // jshint ignore:line +} + +var templatePool = avalon.templateCache = {} + +bindingHandlers.attr = function(data, vmodels) { + var text = data.value.trim(), + simple = true + if (text.indexOf(openTag) > -1 && text.indexOf(closeTag) > 2) { + simple = false + if (rexpr.test(text) && RegExp.rightContext === "" && RegExp.leftContext === "") { + simple = true + text = RegExp.$1 + } + } + if (data.type === "include") { + var elem = data.element + data.includeRendered = getBindingCallback(elem, "data-include-rendered", vmodels) + data.includeLoaded = getBindingCallback(elem, "data-include-loaded", vmodels) + var outer = data.includeReplace = !! avalon(elem).data("includeReplace") + if (avalon(elem).data("includeCache")) { + data.templateCache = {} + } + data.startInclude = DOC.createComment("ms-include") + data.endInclude = DOC.createComment("ms-include-end") + if (outer) { + data.element = data.startInclude + elem.parentNode.insertBefore(data.startInclude, elem) + elem.parentNode.insertBefore(data.endInclude, elem.nextSibling) + } else { + elem.insertBefore(data.startInclude, elem.firstChild) + elem.appendChild(data.endInclude) + } + } + data.handlerName = "attr" //handleName用于处ç†å¤šç§ç»‘定共用åŒä¸€ç§bindingExecutor的情况 + parseExprProxy(text, vmodels, data, (simple ? 0 : scanExpr(data.value))) +} + +bindingExecutors.attr = function(val, elem, data) { + var method = data.type, + attrName = data.param + if (method === "css") { + avalon(elem).css(attrName, val) + } else if (method === "attr") { + + // ms-attr-class="xxx" vm.xxx="aaa bbb ccc"将元素的className设置为aaa bbb ccc + // ms-attr-class="xxx" vm.xxx=false 清空元素的所有类å + // ms-attr-name="yyy" vm.yyy="ooo" 为元素设置name属性 + var toRemove = (val === false) || (val === null) || (val === void 0) + + if (!W3C && propMap[attrName]) { //æ—§å¼IE下需è¦è¿›è¡Œå字映射 + attrName = propMap[attrName] + } + var bool = boolMap[attrName] + if (typeof elem[bool] === "boolean") { + elem[bool] = !! val //布尔属性必须使用el.xxx = true|falseæ–¹å¼è®¾å€¼ + if (!val) { //如果为false, IE全系列下相当于setAttribute(xxx,''),会影å“到样å¼,需è¦è¿›ä¸€æ­¥å¤„ç† + toRemove = true + } + } + if (toRemove) { + return elem.removeAttribute(attrName) + } + //SVGåªèƒ½ä½¿ç”¨setAttribute(xxx, yyy), VMLåªèƒ½ä½¿ç”¨elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy + var isInnate = rsvg.test(elem) ? false : (DOC.namespaces && isVML(elem)) ? true : attrName in elem.cloneNode(false) + if (isInnate) { + elem[attrName] = val+"" + } else { + elem.setAttribute(attrName, val) + } + } else if (method === "include" && val) { + var vmodels = data.vmodels + var rendered = data.includeRendered + var loaded = data.includeLoaded + var replace = data.includeReplace + var target = replace ? elem.parentNode : elem + var scanTemplate = function(text) { + if (loaded) { + var newText = loaded.apply(target, [text].concat(vmodels)) + if (typeof newText === "string") + text = newText + } + if (rendered) { + checkScan(target, function() { + rendered.call(target) + }, NaN) + } + var lastID = data.includeLastID + if (data.templateCache && lastID && lastID !== val) { + var lastTemplate = data.templateCache[lastID] + if (!lastTemplate) { + lastTemplate = data.templateCache[lastID] = DOC.createElement("div") + ifGroup.appendChild(lastTemplate) + } + } + data.includeLastID = val + while (true) { + var node = data.startInclude.nextSibling + if (node && node !== data.endInclude) { + target.removeChild(node) + if (lastTemplate) + lastTemplate.appendChild(node) + } else { + break + } + } + var dom = getTemplateNodes(data, val, text) + var nodes = avalon.slice(dom.childNodes) + target.insertBefore(dom, data.endInclude) + scanNodeArray(nodes, vmodels) + } + + if (data.param === "src") { + if (typeof templatePool[val] === "string") { + avalon.nextTick(function() { + scanTemplate(templatePool[val]) + }) + } else if (Array.isArray(templatePool[val])) { //#805 防止在循环绑定中å‘出许多相åŒçš„请求 + templatePool[val].push(scanTemplate) + } else { + var xhr = getXHR() + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + var s = xhr.status + if (s >= 200 && s < 300 || s === 304 || s === 1223) { + var text = xhr.responseText + for (var f = 0, fn; fn = templatePool[val][f++];) { + fn(text) + } + templatePool[val] = text + } + } + } + templatePool[val] = [scanTemplate] + xhr.open("GET", val, true) + if ("withCredentials" in xhr) { + xhr.withCredentials = true + } + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") + xhr.send(null) + } + } else { + //IE系列与够新的标准æµè§ˆå™¨æ”¯æŒé€šè¿‡IDå–得元素(firefox14+) + //http://tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ + var el = val && val.nodeType === 1 ? val : DOC.getElementById(val) + if (el) { + if (el.tagName === "NOSCRIPT" && !(el.innerHTML || el.fixIE78)) { //IE7-8 innerText,innerHTML都无法å–得其内容,IE6能å–å¾—å…¶innerHTML + xhr = getXHR() //IE9-11与chromeçš„innerHTML会得到转义的内容,它们的innerTextå¯ä»¥ + xhr.open("GET", location, false) //谢谢Nodejs 乱炖群 深圳-纯属虚构 + xhr.send(null) + //http://bbs.csdn.net/topics/390349046?page=1#post-393492653 + var noscripts = DOC.getElementsByTagName("noscript") + var array = (xhr.responseText || "").match(rnoscripts) || [] + var n = array.length + for (var i = 0; i < n; i++) { + var tag = noscripts[i] + if (tag) { //IE6-8中noscript标签的innerHTML,innerText是åªè¯»çš„ + tag.style.display = "none" //http://haslayout.net/css/noscript-Ghost-Bug + tag.fixIE78 = (array[i].match(rnoscriptText) || ["", " "])[1] + } + } + } + avalon.nextTick(function() { + scanTemplate(el.fixIE78 || el.value || el.innerText || el.innerHTML) + }) + } + } + } else { + if (!root.hasAttribute && typeof val === "string" && (method === "src" || method === "href")) { + val = val.replace(/&/g, "&") //处ç†IE67自动转义的问题 + } + elem[method] = val + if (window.chrome && elem.tagName === "EMBED") { + var parent = elem.parentNode //#525 chrome1-37下embed标签动æ€è®¾ç½®srcä¸èƒ½å‘生请求 + var comment = document.createComment("ms-src") + parent.replaceChild(comment, elem) + parent.replaceChild(elem, comment) + } + } +} + +function getTemplateNodes(data, id, text) { + var div = data.templateCache && data.templateCache[id] + if (div) { + var dom = DOC.createDocumentFragment(), + firstChild + while (firstChild = div.firstChild) { + dom.appendChild(firstChild) + } + return dom + } + return avalon.parseHTML(text) +} + +//这几个指令都å¯ä»¥ä½¿ç”¨æ’值表达å¼ï¼Œå¦‚ms-src="aaa/{{b}}/{{c}}.html" +"title,alt,src,value,css,include,href".replace(rword, function(name) { + bindingHandlers[name] = bindingHandlers.attr +}) +//æ ¹æ®VM的属性值或表达å¼çš„值切æ¢ç±»å,ms-class="xxx yyy zzz:flag" +//http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html +bindingHandlers["class"] = function(data, vmodels) { + var oldStyle = data.param, + text = data.value, + rightExpr + data.handlerName = "class" + if (!oldStyle || isFinite(oldStyle)) { + data.param = "" //去掉数字 + var noExpr = text.replace(rexprg, function(a) { + return a.replace(/./g, "0") + //return Math.pow(10, a.length - 1) //å°†æ’值表达å¼æ’å…¥10çš„N-1次方æ¥å ä½ + }) + var colonIndex = noExpr.indexOf(":") //å–得第一个冒å·çš„ä½ç½® + if (colonIndex === -1) { // 比如 ms-class="aaa bbb ccc" 的情况 + var className = text + } else { // 比如 ms-class-1="ui-state-active:checked" 的情况 + className = text.slice(0, colonIndex) + rightExpr = text.slice(colonIndex + 1) + parseExpr(rightExpr, vmodels, data) //决定是添加还是删除 + if (!data.evaluator) { + log("debug: ms-class '" + (rightExpr || "").trim() + "' ä¸å­˜åœ¨äºŽVM中") + return false + } else { + data._evaluator = data.evaluator + data._args = data.args + } + } + var hasExpr = rexpr.test(className) //比如ms-class="width{{w}}"的情况 + if (!hasExpr) { + data.immobileClass = className + } + parseExprProxy("", vmodels, data, (hasExpr ? scanExpr(className) : 0)) + } else { + data.immobileClass = data.oldStyle = data.param + parseExprProxy(text, vmodels, data) + } +} + +bindingExecutors["class"] = function(val, elem, data) { + var $elem = avalon(elem), + method = data.type + if (method === "class" && data.oldStyle) { //如果是旧风格 + $elem.toggleClass(data.oldStyle, !! val) + } else { + //如果存在冒å·å°±æœ‰æ±‚值函数 + data.toggleClass = data._evaluator ? !! data._evaluator.apply(elem, data._args) : true + data.newClass = data.immobileClass || val + if (data.oldClass && data.newClass !== data.oldClass) { + $elem.removeClass(data.oldClass) + } + data.oldClass = data.newClass + switch (method) { + case "class": + $elem.toggleClass(data.newClass, data.toggleClass) + break + case "hover": + case "active": + if (!data.hasBindEvent) { //ç¡®ä¿åªç»‘定一次 + var activate = "mouseenter" //在移出移入时切æ¢ç±»å + var abandon = "mouseleave" + if (method === "active") { //在èšç„¦å¤±ç„¦ä¸­åˆ‡æ¢ç±»å + elem.tabIndex = elem.tabIndex || -1 + activate = "mousedown" + abandon = "mouseup" + var fn0 = $elem.bind("mouseleave", function() { + data.toggleClass && $elem.removeClass(data.newClass) + }) + } + var fn1 = $elem.bind(activate, function() { + data.toggleClass && $elem.addClass(data.newClass) + }) + var fn2 = $elem.bind(abandon, function() { + data.toggleClass && $elem.removeClass(data.newClass) + }) + data.rollback = function() { + $elem.unbind("mouseleave", fn0) + $elem.unbind(activate, fn1) + $elem.unbind(abandon, fn2) + } + data.hasBindEvent = true + } + break; + } + } +} + +"hover,active".replace(rword, function(method) { + bindingHandlers[method] = bindingHandlers["class"] +}) +//ms-controller绑定已ç»åœ¨scanTag 方法中实现 +//ms-css绑定已由ms-attr绑定实现 + + +// bindingHandlers.data 定义在if.js +bindingExecutors.data = function(val, elem, data) { + var key = "data-" + data.param + if (val && typeof val === "object") { + elem[key] = val + } else { + elem.setAttribute(key, String(val)) + } +} +//åŒå·¥ç»‘定 +var duplexBinding = bindingHandlers.duplex = function(data, vmodels) { + var elem = data.element, + hasCast + parseExprProxy(data.value, vmodels, data, 0, 1) + + data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop + if (data.evaluator && data.args) { + var params = [] + var casting = oneObject("string,number,boolean,checked") + if (elem.type === "radio" && data.param === "") { + data.param = "checked" + } + if (elem.msData) { + elem.msData["ms-duplex"] = data.value + } + data.param.replace(/\w+/g, function(name) { + if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) { + if (name === "radio") + log("ms-duplex-radioå·²ç»æ›´å为ms-duplex-checked") + name = "checked" + data.isChecked = true + } + if (name === "bool") { + name = "boolean" + log("ms-duplex-boolå·²ç»æ›´å为ms-duplex-boolean") + } else if (name === "text") { + name = "string" + log("ms-duplex-textå·²ç»æ›´å为ms-duplex-string") + } + if (casting[name]) { + hasCast = true + } + avalon.Array.ensure(params, name) + }) + if (!hasCast) { + params.push("string") + } + data.param = params.join("-") + data.bound = function(type, callback) { + if (elem.addEventListener) { + elem.addEventListener(type, callback, false) + } else { + elem.attachEvent("on" + type, callback) + } + var old = data.rollback + data.rollback = function() { + elem.avalonSetter = null + avalon.unbind(elem, type, callback) + old && old() + } + } + for (var i in avalon.vmodels) { + var v = avalon.vmodels[i] + v.$fire("avalon-ms-duplex-init", data) + } + var cpipe = data.pipe || (data.pipe = pipe) + cpipe(null, data, "init") + var tagName = elem.tagName + duplexBinding[tagName] && duplexBinding[tagName](elem, data.evaluator.apply(null, data.args), data) + } +} +//ä¸å­˜åœ¨ bindingExecutors.duplex + + function fixNull(val) { + return val == null ? "" : val + } +avalon.duplexHooks = { + checked: { + get: function(val, data) { + return !data.element.oldValue + } + }, + string: { + get: function(val) { //åŒæ­¥åˆ°VM + return val + }, + set: fixNull + }, + "boolean": { + get: function(val) { + return val === "true" + }, + set: fixNull + }, + number: { + get: function(val, data) { + var number = parseFloat(val) + if (-val === -number) { + return number + } + var arr = /strong|medium|weak/.exec(data.element.getAttribute("data-duplex-number")) || ["medium"] + switch (arr[0]) { + case "strong": + return 0 + case "medium": + return val === "" ? "" : 0 + case "weak": + return val + } + }, + set: fixNull + } +} + +function pipe(val, data, action, e) { + data.param.replace(/\w+/g, function(name) { + var hook = avalon.duplexHooks[name] + if (hook && typeof hook[action] === "function") { + val = hook[action](val, data) + } + }) + return val +} + +var TimerID, ribbon = [] + + avalon.tick = function(fn) { + if (ribbon.push(fn) === 1) { + TimerID = setInterval(ticker, 60) + } + } + + function ticker() { + for (var n = ribbon.length - 1; n >= 0; n--) { + var el = ribbon[n] + if (el() === false) { + ribbon.splice(n, 1) + } + } + if (!ribbon.length) { + clearInterval(TimerID) + } + } + +var watchValueInTimer = noop +var rmsinput = /text|password|hidden/ +new function() { // jshint ignore:line + try { //#272 IE9-IE11, firefox + var setters = {} + var aproto = HTMLInputElement.prototype + var bproto = HTMLTextAreaElement.prototype + function newSetter(value) { // jshint ignore:line + setters[this.tagName].call(this, value) + if (rmsinput.test(this.type) && !this.msFocus && this.avalonSetter) { + this.avalonSetter() + } + } + var inputProto = HTMLInputElement.prototype + Object.getOwnPropertyNames(inputProto) //æ•…æ„引å‘IE6-8ç­‰æµè§ˆå™¨æŠ¥é”™ + setters["INPUT"] = Object.getOwnPropertyDescriptor(aproto, "value").set + + Object.defineProperty(aproto, "value", { + set: newSetter + }) + setters["TEXTAREA"] = Object.getOwnPropertyDescriptor(bproto, "value").set + Object.defineProperty(bproto, "value", { + set: newSetter + }) + } catch (e) { + //在chrome 43中 ms-duplex终于ä¸éœ€è¦ä½¿ç”¨å®šæ—¶å™¨å®žçŽ°åŒå‘绑定了 + // http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype + // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1 + watchValueInTimer = avalon.tick + } +} // jshint ignore:line +if (IEVersion) { + avalon.bind(DOC, "selectionchange", function(e) { + var el = DOC.activeElement + if (el && typeof el.avalonSetter === "function") { + el.avalonSetter() + } + }) +} + +//处ç†radio, checkbox, text, textarea, password +duplexBinding.INPUT = function(element, evaluator, data) { + var $type = element.type, + bound = data.bound, + $elem = avalon(element), + composing = false + + function callback(value) { + data.changed.call(this, value, data) + } + + function compositionStart() { + composing = true + } + + function compositionEnd() { + composing = false + } + //当valueå˜åŒ–时改å˜model的值 + var updateVModel = function() { + if (composing) //处ç†ä¸­æ–‡è¾“入法在minlengh下引å‘çš„BUG + return + var val = element.oldValue = element.value //防止递归调用形æˆæ­»å¾ªçŽ¯ + var lastValue = data.pipe(val, data, "get") + if ($elem.data("duplexObserve") !== false) { + evaluator(lastValue) + callback.call(element, lastValue) + if ($elem.data("duplex-focus")) { + avalon.nextTick(function() { + element.focus() + }) + } + } + } + //当modelå˜åŒ–æ—¶,它就会改å˜value的值 + data.handler = function() { + var val = data.pipe(evaluator(), data, "set") + "" //fix #673 + if (val !== element.oldValue) { + element.value = val + } + } + if (data.isChecked || $type === "radio") { + var IE6 = IEVersion === 6 + updateVModel = function() { + if ($elem.data("duplexObserve") !== false) { + var lastValue = data.pipe(element.value, data, "get") + evaluator(lastValue) + callback.call(element, lastValue) + } + } + data.handler = function() { + var val = evaluator() + var checked = data.isChecked ? !! val : val + "" === element.value + element.oldValue = checked + if (IE6) { + setTimeout(function() { + //IE8 checkbox, radio是使用defaultChecked控制选中状æ€ï¼Œ + //并且è¦å…ˆè®¾ç½®defaultCheckedåŽè®¾ç½®checked + //并且必须设置延迟 + element.defaultChecked = checked + element.checked = checked + }, 31) + } else { + element.checked = checked + } + } + bound("click", updateVModel) + } else if ($type === "checkbox") { + updateVModel = function() { + if ($elem.data("duplexObserve") !== false) { + var method = element.checked ? "ensure" : "remove" + var array = evaluator() + if (!Array.isArray(array)) { + log("ms-duplex应用于checkbox上è¦å¯¹åº”一个数组") + array = [array] + } + var val = data.pipe(element.value, data, "get") + avalon.Array[method](array, val) + callback.call(element, array) + } + } + + data.handler = function() { + var array = [].concat(evaluator()) //强制转æ¢ä¸ºæ•°ç»„ + var val = data.pipe(element.value, data, "get") + element.checked = array.indexOf(val) > -1 + } + bound(W3C ? "change" : "click", updateVModel) + } else { + var events = element.getAttribute("data-duplex-event") || "input" + if (element.attributes["data-event"]) { + log("data-event指令已ç»åºŸå¼ƒï¼Œè¯·æ”¹ç”¨data-duplex-event") + } + + function delay(e) { // jshint ignore:line + setTimeout(function() { + updateVModel(e) + }) + } + events.replace(rword, function(name) { + switch (name) { + case "input": + if (!IEVersion) { // W3C + bound("input", updateVModel) + //éžIEæµè§ˆå™¨æ‰ç”¨è¿™ä¸ª + bound("compositionstart", compositionStart) + bound("compositionend", compositionEnd) + bound("DOMAutoComplete", updateVModel) + } else { //onpropertychange事件无法区分是程åºè§¦å‘è¿˜æ˜¯ç”¨æˆ·è§¦å‘ + // IE下通过selectionchange事件监å¬IE9+点击inputå³è¾¹çš„X的清空行为,åŠç²˜è´´ï¼Œå‰ªåˆ‡ï¼Œåˆ é™¤è¡Œä¸º + if (IEVersion > 8) { + bound("input", updateVModel) //IE9使用propertychange无法监å¬ä¸­æ–‡è¾“入改动 + } else { + bound("propertychange", function(e) { //IE6-8下第一次修改时ä¸ä¼šè§¦å‘,需è¦ä½¿ç”¨keydown或selectionchange修正 + if (e.propertyName === "value") { + updateVModel() + } + }) + } + bound("dragend", delay) + //http://www.cnblogs.com/rubylouvre/archive/2013/02/17/2914604.html + //http://www.matts411.com/post/internet-explorer-9-oninput/ + } + break + default: + bound(name, updateVModel) + break + } + }) + bound("focus", function() { + element.msFocus = true + }) + bound("blur", function() { + element.msFocus = false + }) + + if (rmsinput.test($type)) { + watchValueInTimer(function() { + if (root.contains(element)) { + if (!element.msFocus && element.oldValue !== element.value) { + updateVModel() + } + } else if (!element.msRetain) { + return false + } + }) + } + + element.avalonSetter = updateVModel //#765 + } + + element.oldValue = element.value + avalon.injectBinding(data) + callback.call(element, element.value) +} +duplexBinding.TEXTAREA = duplexBinding.INPUT +duplexBinding.SELECT = function(element, evaluator, data) { + var $elem = avalon(element) + + function updateVModel() { + if ($elem.data("duplexObserve") !== false) { + var val = $elem.val() //字符串或字符串数组 + if (Array.isArray(val)) { + val = val.map(function(v) { + return data.pipe(v, data, "get") + }) + } else { + val = data.pipe(val, data, "get") + } + if (val + "" !== element.oldValue) { + evaluator(val) + } + data.changed.call(element, val, data) + } + } + data.handler = function() { + var val = evaluator() + val = val && val.$model || val + if (Array.isArray(val)) { + if (!element.multiple) { + log("ms-duplex在ä¸èƒ½å¯¹åº”一个数组") + } + } + //å¿…é¡»å˜æˆå­—符串åŽæ‰èƒ½æ¯”较 + val = Array.isArray(val) ? val.map(String) : val + "" + if (val + "" !== element.oldValue) { + $elem.val(val) + element.oldValue = val + "" + } + } + data.bound("change", updateVModel) + element.msCallback = function() { + avalon.injectBinding(data) + data.changed.call(element, evaluator(), data) + } +} +// bindingHandlers.html 定义在if.js +bindingExecutors.html = function (val, elem, data) { + var isHtmlFilter = elem.nodeType !== 1 + var parent = isHtmlFilter ? elem.parentNode : elem + if (!parent) + return + val = val == null ? "" : val + if (data.oldText !== val) { + data.oldText = val + } else { + return + } + if (elem.nodeType === 3) { + var signature = generateID("html") + parent.insertBefore(DOC.createComment(signature), elem) + data.element = DOC.createComment(signature + ":end") + parent.replaceChild(data.element, elem) + elem = data.element + } + if (typeof val !== "object") {//string, number, boolean + var fragment = avalon.parseHTML(String(val)) + } else if (val.nodeType === 11) { //å°†val转æ¢ä¸ºæ–‡æ¡£ç¢Žç‰‡ + fragment = val + } else if (val.nodeType === 1 || val.item) { + var nodes = val.nodeType === 1 ? val.childNodes : val.item + fragment = avalonFragment.cloneNode(true) + while (nodes[0]) { + fragment.appendChild(nodes[0]) + } + } + + nodes = avalon.slice(fragment.childNodes) + //æ’å…¥å ä½ç¬¦, 如果是过滤器,需è¦æœ‰èŠ‚制地移除指定的数é‡,如果是html指令,直接清空 + if (isHtmlFilter) { + var endValue = elem.nodeValue.slice(0, -4) + while (true) { + var node = elem.previousSibling + if (!node || node.nodeType === 8 && node.nodeValue === endValue) { + break + } else { + parent.removeChild(node) + } + } + parent.insertBefore(fragment, elem) + } else { + avalon.clearHTML(elem).appendChild(fragment) + } + scanNodeArray(nodes, data.vmodels) +} +bindingHandlers["if"] = + bindingHandlers.data = + bindingHandlers.text = + bindingHandlers.html = + function(data, vmodels) { + parseExprProxy(data.value, vmodels, data) +} + +bindingExecutors["if"] = function(val, elem, data) { + try { + if(!elem.parentNode) return + } catch(e) {return} + if (val) { //æ’回DOMæ ‘ + if (elem.nodeType === 8) { + elem.parentNode.replaceChild(data.template, elem) + // animate.enter(data.template, elem.parentNode) + elem = data.element = data.template //这时å¯èƒ½ä¸ºnull + } + if (elem.getAttribute(data.name)) { + elem.removeAttribute(data.name) + scanAttr(elem, data.vmodels) + } + data.rollback = null + } else { //移出DOM树,并用注释节点å æ®åŽŸä½ç½® + if (elem.nodeType === 1) { + var node = data.element = DOC.createComment("ms-if") + elem.parentNode.replaceChild(node, elem) + // animate.leave(elem, node.parentNode, node) + data.template = elem //元素节点 + ifGroup.appendChild(elem) + data.rollback = function() { + if (elem.parentNode === ifGroup) { + ifGroup.removeChild(elem) + } + } + } + } +} +//ms-important绑定已ç»åœ¨scanTag 方法中实现 +//ms-include绑定已由ms-attr绑定实现 + +var rdash = /\(([^)]*)\)/ +bindingHandlers.on = function(data, vmodels) { + var value = data.value + data.type = "on" + var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10 + if (typeof bindingHandlers.on[eventType + "Hook"] === "function") { + bindingHandlers.on[eventType + "Hook"](data) + } + if (value.indexOf("(") > 0 && value.indexOf(")") > -1) { + var matched = (value.match(rdash) || ["", ""])[1].trim() + if (matched === "" || matched === "$event") { // aaa() aaa($event)当æˆaaaå¤„ç† + value = value.replace(rdash, "") + } + } + parseExprProxy(value, vmodels, data) +} + +bindingExecutors.on = function(callback, elem, data) { + callback = function(e) { + var fn = data.evaluator || noop + return fn.apply(this, data.args.concat(e)) + } + var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10 + if (eventType === "scan") { + callback.call(elem, { + type: eventType + }) + } else if (typeof data.specialBind === "function") { + data.specialBind(elem, callback) + } else { + var removeFn = avalon.bind(elem, eventType, callback) + } + data.rollback = function() { + if (typeof data.specialUnbind === "function") { + data.specialUnbind() + } else { + avalon.unbind(elem, eventType, removeFn) + } + } +} +bindingHandlers.repeat = function (data, vmodels) { + var type = data.type + parseExprProxy(data.value, vmodels, data, 0, 1) + data.proxies = [] + var freturn = false + try { + var $repeat = data.$repeat = data.evaluator.apply(0, data.args || []) + var xtype = avalon.type($repeat) + if (xtype !== "object" && xtype !== "array") { + freturn = true + avalon.log("warning:" + data.value + "åªèƒ½æ˜¯å¯¹è±¡æˆ–数组") + } + } catch (e) { + freturn = true + } + var arr = data.value.split(".") || [] + if (arr.length > 1) { + arr.pop() + var n = arr[0] + for (var i = 0, v; v = vmodels[i++]; ) { + if (v && v.hasOwnProperty(n)) { + var events = v[n].$events || {} + events[subscribers] = events[subscribers] || [] + events[subscribers].push(data) + break + } + } + } + + var elem = data.element + if (elem.nodeType === 1) { + elem.removeAttribute(data.name) + data.sortedCallback = getBindingCallback(elem, "data-with-sorted", vmodels) + data.renderedCallback = getBindingCallback(elem, "data-" + type + "-rendered", vmodels) + var signature = generateID(type) + var start = DOC.createComment(signature) + var end = DOC.createComment(signature + ":end") + data.signature = signature + data.template = avalonFragment.cloneNode(false) + if (type === "repeat") { + var parent = elem.parentNode + parent.replaceChild(end, elem) + parent.insertBefore(start, end) + data.template.appendChild(elem) + } else { + while (elem.firstChild) { + data.template.appendChild(elem.firstChild) + } + elem.appendChild(start) + elem.appendChild(end) + } + data.element = end + data.handler = bindingExecutors.repeat + data.rollback = function () { + var elem = data.element + if (!elem) + return + data.handler("clear") + } + } + + if (freturn) { + return + } + + data.$outer = {} + var check0 = "$key" + var check1 = "$val" + if (Array.isArray($repeat)) { + check0 = "$first" + check1 = "$last" + } + + for (i = 0; v = vmodels[i++]; ) { + if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) { + data.$outer = v + break + } + } + var $events = $repeat.$events + var $list = ($events || {})[subscribers] + injectDependency($list, data) + if (xtype === "object") { + data.$with = true + $repeat.$proxy || ($repeat.$proxy = {}) + data.handler("append", $repeat) + } else if ($repeat.length) { + data.handler("add", 0, $repeat.length) + } +} + +bindingExecutors.repeat = function (method, pos, el) { + if (!method && this.$with) { + method = "append" + var flag = "update" + } + if (method) { + var data = this, start, fragment + var end = data.element + var comments = getComments(data) + var parent = end.parentNode + var proxies = data.proxies + var transation = avalonFragment.cloneNode(false) + switch (method) { + case "add": //在posä½ç½®åŽæ·»åŠ el数组(pos为æ’å…¥ä½ç½®,el为è¦æ’入的个数) + var n = pos + el + var fragments = [] + for (var i = pos; i < n; i++) { + var proxy = eachProxyAgent(i, data) + proxies.splice(i, 0, proxy) + shimController(data, transation, proxy, fragments) + } + var now = new Date() - 0 + avalon.optimize = avalon.optimize || now + for (i = 0; fragment = fragments[i++]; ) { + scanNodeArray(fragment.nodes, fragment.vmodels) + fragment.nodes = fragment.vmodels = null + } + if (avalon.optimize === now) { + avalon.optimize = null + } + parent.insertBefore(transation, comments[pos] || end) + avalon.profile("æ’å…¥æ“作花费了 " + (new Date - now)) + break + case "del": //å°†posåŽçš„el个元素删掉(pos, el都是数字) + sweepNodes(comments[pos], comments[pos + el] || end) + var removed = proxies.splice(pos, el) + recycleProxies(removed, "each") + break + case "clear": + start = comments[0] + if (start) { + sweepNodes(start, end) + if (data.$with) { + parent.insertBefore(start, end) + } + } + recycleProxies(proxies, "each") + break + case "move": + start = comments[0] + if (start) { + var signature = start.nodeValue + var rooms = [] + var room = [], + node + sweepNodes(start, end, function () { + room.unshift(this) + if (this.nodeValue === signature) { + rooms.unshift(room) + room = [] + } + }) + sortByIndex(rooms, pos) + sortByIndex(proxies, pos) + while (room = rooms.shift()) { + while (node = room.shift()) { + transation.appendChild(node) + } + } + parent.insertBefore(transation, end) + } + break + case "index": //å°†proxies中的第pos个起的所有元素é‡æ–°ç´¢å¼• + var last = proxies.length - 1 + for (; el = proxies[pos]; pos++) { + el.$index = pos + el.$first = pos === 0 + el.$last = pos === last + } + return + case "set": //å°†proxies中的第pos个元素的VM设置为el(pos为数字,elä»»æ„) + proxy = proxies[pos] + if (proxy) { + fireDependencies(proxy.$events[data.param || "el"]) + } + break + case "append": + var object = data.$repeat //原æ¥ç¬¬2å‚数, 被循环对象 + var oldProxy = object.$proxy //代ç†å¯¹è±¡ç»„æˆçš„hash + var keys = [] + now = new Date() - 0 + avalon.optimize = avalon.optimize || now + if (flag === "update") { + if (!data.evaluator) { + parseExprProxy(data.value, data.vmodels, data, 0, 1) + } + object = data.$repeat = data.evaluator.apply(0, data.args || []) + object.$proxy = oldProxy + } + var pool = object.$proxy || {} + removed = [] + var nodes = data.element.parentNode.childNodes + var add = false + for (i = 0; node = nodes[i++]; ) { + if (node.nodeValue === data.signature) { + add = true + } else if (node.nodeValue === data.signature + ":end") { + add = false + } + if (add) { + removed.push(node) + } + } + + var indexNode = [], item + var keyIndex = data.keyIndex || (data.keyIndex = {}) + //将现有的节点全部移出DOMæ ‘ + for ( i = 0; i < removed.length; i++) { + el = removed[i] + if (el.nodeValue === data.signature) { + item = avalonFragment.cloneNode(false) + indexNode.push(item) + } + item.appendChild(el) + } + + + for (var key in object) { //当å‰å¯¹è±¡çš„所有键å + if (object.hasOwnProperty(key) && key !== "hasOwnProperty" && key !== "$proxy") { + keys.push(key) + } + } + + for (var i = 0; key = keys[i++]; ) { + if (!pool.hasOwnProperty(key)) {//添加缺失的代ç†VM + pool[key] = withProxyAgent(pool[key], key, data) + } else { + pool[key].$val = object[key] + } + } + + for ( key in pool) { + if (keys.indexOf(key) === -1) {//删除没用的代ç†VM + proxyRecycler(pool[key], withProxyPool) //去掉之å‰çš„代ç†VM + delete pool[key] + } + } + var fragments = [] + var renderKeys = keys //需è¦æ¸²æŸ“到DOM树去的键å + var end = data.element + if (data.sortedCallback) { //å¦‚æžœæœ‰å›žè°ƒï¼Œåˆ™è®©å®ƒä»¬æŽ’åº + var keys2 = data.sortedCallback.call(parent, keys) + if (keys2 && Array.isArray(keys2)) { + renderKeys = keys2 + } + } + + for (i = 0; i < renderKeys.length; i++) { + key = renderKeys[i] + if (typeof keyIndex[key] === "number") { + transation.appendChild(indexNode[keyIndex[key]]) + fragments.push({}) + } else { + shimController(data, transation, pool[key], fragments) + } + } + + for (i = 0; i < renderKeys.length; i++) { + keyIndex[renderKeys[i]] = i + } + + for (i = 0; fragment = fragments[i++]; ) { + if (fragment.nodes) { + scanNodeArray(fragment.nodes, fragment.vmodels) + fragment.nodes = fragment.vmodels = null + } + } + if (avalon.optimize === now) { + avalon.optimize = null + } + parent.insertBefore(transation, end) + avalon.profile("æ’å…¥æ“作花费了 " + (new Date - now)) + break + } + if (!data.$repeat || data.$repeat.hasOwnProperty("$lock")) //IE6-8 VBScript对象会报错, 有时候data.$repeatä¸å­˜åœ¨ + return + if (method === "clear") + method = "del" + var callback = data.renderedCallback || noop, + args = arguments + if (parent.oldValue && parent.tagName === "SELECT") { //fix #503 + avalon(parent).val(parent.oldValue.split(",")) + } + callback.apply(parent, args) + } +} +"with,each".replace(rword, function (name) { + bindingHandlers[name] = bindingHandlers.repeat +}) + +function shimController(data, transation, proxy, fragments) { + var content = data.template.cloneNode(true) + var nodes = avalon.slice(content.childNodes) + content.insertBefore(DOC.createComment(data.signature), content.firstChild) + transation.appendChild(content) + var nv = [proxy].concat(data.vmodels) + var fragment = { + nodes: nodes, + vmodels: nv + } + fragments.push(fragment) +} + +function getComments(data) { + var ret = [] + var nodes = data.element.parentNode.childNodes + for(var i= 0, node; node = nodes[i++];){ + if(node.nodeValue === data.signature){ + ret.push( node ) + }else if(node.nodeValue === data.signature+":end"){ + break + } + } + return ret +} + + +//移除掉start与end之间的节点(ä¿ç•™end) +function sweepNodes(start, end, callback) { + while (true) { + var node = end.previousSibling + if (!node) + break + node.parentNode.removeChild(node) + callback && callback.call(node) + if (node === start) { + break + } + } +} + +// 为ms-each,ms-with, ms-repeat会创建一个代ç†VM, +// 通过它们ä¿æŒä¸€ä¸ªä¸‹ä¸Šæ–‡ï¼Œè®©ç”¨æˆ·èƒ½è°ƒç”¨$index,$first,$last,$remove,$key,$val,$outer等属性与方法 +// 所有代ç†VM的产生,消费,收集,存放通过xxxProxyFactory,xxxProxyAgent, recycleProxies,xxxProxyPool实现 +var withProxyPool = [] +function withProxyFactory() { + var proxy = modelFactory({ + $key: "", + $outer: {}, + $host: {}, + $val: { + get: function () { + return this.$host[this.$key] + }, + set: function (val) { + this.$host[this.$key] = val + } + } + }, { + $val: 1 + }) + proxy.$id = generateID("$proxy$with") + return proxy +} + +function withProxyAgent(proxy, key, data) { + proxy = proxy || withProxyPool.pop() + if (!proxy) { + proxy = withProxyFactory() + } else { + proxy.$reinitialize() + } + var host = data.$repeat + proxy.$key = key + proxy.$host = host + proxy.$outer = data.$outer + if (host.$events) { + proxy.$events.$val = host.$events[key] + } else { + proxy.$events = {} + } + return proxy +} + + +function recycleProxies(proxies) { + eachProxyRecycler(proxies) +} +function eachProxyRecycler(proxies) { + proxies.forEach(function (proxy) { + proxyRecycler(proxy, eachProxyPool) + }) + proxies.length = 0 +} + + +var eachProxyPool = [] +function eachProxyFactory(name) { + var source = { + $host: [], + $outer: {}, + $index: 0, + $first: false, + $last: false, + $remove: avalon.noop + } + source[name] = { + get: function () { + var e = this.$events + var array = e.$index + e.$index = e[name] //#817 通过$index为el收集ä¾èµ– + try { + return this.$host[this.$index] + } finally { + e.$index = array + } + }, + set: function (val) { + try { + var e = this.$events + var array = e.$index + e.$index = [] + this.$host.set(this.$index, val) + } finally { + e.$index = array + } + } + } + var second = { + $last: 1, + $first: 1, + $index: 1 + } + var proxy = modelFactory(source, second) + proxy.$id = generateID("$proxy$each") + return proxy +} + +function eachProxyAgent(index, data) { + var param = data.param || "el", + proxy + for (var i = 0, n = eachProxyPool.length; i < n; i++) { + var candidate = eachProxyPool[i] + if (candidate && candidate.hasOwnProperty(param)) { + proxy = candidate + eachProxyPool.splice(i, 1) + } + } + if (!proxy) { + proxy = eachProxyFactory(param) + } + var host = data.$repeat + var last = host.length - 1 + proxy.$index = index + proxy.$first = index === 0 + proxy.$last = index === last + proxy.$host = host + proxy.$outer = data.$outer + proxy.$remove = function () { + return host.removeAt(proxy.$index) + } + return proxy +} + + +function proxyRecycler(proxy, proxyPool) { + for (var i in proxy.$events) { + if (Array.isArray(proxy.$events[i])) { + proxy.$events[i].forEach(function (data) { + if (typeof data === "object") + disposeData(data) + })// jshint ignore:line + proxy.$events[i].length = 0 + } + } + proxy.$host = proxy.$outer = {} + if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) { + proxyPool.pop() + } +} +/********************************************************************* + * å„ç§æŒ‡ä»¤ * + **********************************************************************/ +//ms-skip绑定已ç»åœ¨scanTag 方法中实现 +// bindingHandlers.text 定义在if.js +bindingExecutors.text = function(val, elem) { + val = val == null ? "" : val //ä¸åœ¨é¡µé¢ä¸Šæ˜¾ç¤ºundefined null + if (elem.nodeType === 3) { //绑定在文本节点上 + try { //IE对游离于DOM树外的节点赋值会报错 + elem.data = val + } catch (e) {} + } else { //绑定在特性节点上 + if ("textContent" in elem) { + elem.textContent = val + } else { + elem.innerText = val + } + } +} +function parseDisplay(nodeName, val) { + //用于å–得此类标签的默认display值 + var key = "_" + nodeName + if (!parseDisplay[key]) { + var node = DOC.createElement(nodeName) + root.appendChild(node) + if (W3C) { + val = getComputedStyle(node, null).display + } else { + val = node.currentStyle.display + } + root.removeChild(node) + parseDisplay[key] = val + } + return parseDisplay[key] +} + +avalon.parseDisplay = parseDisplay + +bindingHandlers.visible = function(data, vmodels) { + var elem = data.element + var display = elem.style.display + if(display === "none"){ + display = parseDisplay(elem.nodeName) + } + data.display = display + parseExprProxy(data.value, vmodels, data) +} + +bindingExecutors.visible = function(val, elem, data) { + elem.style.display = val ? data.display : "none" +} +bindingHandlers.widget = function(data, vmodels) { + var args = data.value.match(rword) + var elem = data.element + var widget = args[0] + var id = args[1] + if (!id || id === "$") { //没有定义或为$时,å–组件å+éšæœºæ•° + id = generateID(widget) + } + var optName = args[2] || widget //没有定义,å–组件å + var constructor = avalon.ui[widget] + if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname" + vmodels = elem.vmodels || vmodels + for (var i = 0, v; v = vmodels[i++];) { + if (v.hasOwnProperty(optName) && typeof v[optName] === "object") { + var vmOptions = v[optName] + vmOptions = vmOptions.$model || vmOptions + break + } + } + if (vmOptions) { + var wid = vmOptions[widget + "Id"] + if (typeof wid === "string") { + log("warning!ä¸å†æ”¯æŒ" + widget + "Id") + id = wid + } + } + //抽å–data-tooltip-textã€data-tooltip-attr属性,组æˆä¸€ä¸ªé…置对象 + var widgetData = avalon.getWidgetData(elem, widget) + data.value = [widget, id, optName].join(",") + data[widget + "Id"] = id + data.evaluator = noop + elem.msData["ms-widget-id"] = id + var options = data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData) + elem.removeAttribute("ms-widget") + var vmodel = constructor(elem, data, vmodels) || {} //防止组件ä¸è¿”回VM + if (vmodel.$id) { + avalon.vmodels[id] = vmodel + createSignalTower(elem, vmodel) + try { + vmodel.$init(function() { + avalon.scan(elem, [vmodel].concat(vmodels)) + if (typeof options.onInit === "function") { + options.onInit.call(elem, vmodel, options, vmodels) + } + }) + } catch (e) {} + data.rollback = function() { + try { + vmodel.widgetElement = null + vmodel.$remove() + } catch (e) {} + elem.msData = {} + delete avalon.vmodels[vmodel.$id] + } + injectDisposeQueue(data, widgetList) + if (window.chrome) { + elem.addEventListener("DOMNodeRemovedFromDocument", function() { + setTimeout(rejectDisposeQueue) + }) + } + } else { + avalon.scan(elem, vmodels) + } + } else if (vmodels.length) { //如果该组件还没有加载,那么ä¿å­˜å½“å‰çš„vmodels + elem.vmodels = vmodels + } +} +var widgetList = [] +//ä¸å­˜åœ¨ bindingExecutors.widget +/********************************************************************* + * 自带过滤器 * + **********************************************************************/ +var rscripts = /]*>([\S\s]*?)<\/script\s*>/gim +var ron = /\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g +var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig +var rsanitize = { + a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig, + img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig, + form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig +} +var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g +var rnoalphanumeric = /([^\#-~| |!])/g; + +function numberFormat(number, decimals, point, thousands) { + //form http://phpjs.org/functions/number_format/ + //number 必需,è¦æ ¼å¼åŒ–çš„æ•°å­— + //decimals å¯é€‰ï¼Œè§„定多少个å°æ•°ä½ã€‚ + //point å¯é€‰ï¼Œè§„定用作å°æ•°ç‚¹çš„字符串(默认为 . )。 + //thousands å¯é€‰ï¼Œè§„定用作åƒä½åˆ†éš”符的字符串(默认为 , ),如果设置了该å‚数,那么所有其他å‚数都是必需的。 + number = (number + '') + .replace(/[^0-9+\-Ee.]/g, '') + var n = !isFinite(+number) ? 0 : +number, + prec = !isFinite(+decimals) ? 3 : Math.abs(decimals), + sep = thousands || ",", + dec = point || ".", + s = '', + toFixedFix = function(n, prec) { + var k = Math.pow(10, prec) + return '' + (Math.round(n * k) / k) + .toFixed(prec) + } + // Fix for IE parseFloat(0.55).toFixed(0) = 0; + s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)) + .split('.') + if (s[0].length > 3) { + s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep) + } + if ((s[1] || '') + .length < prec) { + s[1] = s[1] || '' + s[1] += new Array(prec - s[1].length + 1) + .join('0') + } + return s.join(dec) +} + + +var filters = avalon.filters = { + uppercase: function(str) { + return str.toUpperCase() + }, + lowercase: function(str) { + return str.toLowerCase() + }, + truncate: function(str, length, truncation) { + //length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串 + length = length || 30 + truncation = typeof truncation === "string" ? truncation : "..." + return str.length > length ? str.slice(0, length - truncation.length) + truncation : String(str) + }, + $filter: function(val) { + for (var i = 1, n = arguments.length; i < n; i++) { + var array = arguments[i] + var fn = avalon.filters[array.shift()] + if (typeof fn === "function") { + var arr = [val].concat(array) + val = fn.apply(null, arr) + } + } + return val + }, + camelize: camelize, + //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet + // chrome + // chrome + // IE67chrome + // IE67chrome + // IE67chrome + sanitize: function(str) { + return str.replace(rscripts, "").replace(ropen, function(a, b) { + var match = a.toLowerCase().match(/<(\w+)\s/) + if (match) { //处ç†a标签的href属性,img标签的src属性,form标签的action属性 + var reg = rsanitize[match[1]] + if (reg) { + a = a.replace(reg, function(s, name, value) { + var quote = value.charAt(0) + return name + "=" + quote + "javascript:void(0)" + quote// jshint ignore:line + }) + } + } + return a.replace(ron, " ").replace(/\s+/g, " ") //移除onXXX事件 + }) + }, + escape: function(str) { + //将字符串ç»è¿‡ str 转义得到适åˆåœ¨é¡µé¢ä¸­æ˜¾ç¤ºçš„内容, ä¾‹å¦‚æ›¿æ¢ < 为 < + return String(str). + replace(/&/g, '&'). + replace(rsurrogate, function(value) { + var hi = value.charCodeAt(0) + var low = value.charCodeAt(1) + return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';' + }). + replace(rnoalphanumeric, function(value) { + return '&#' + value.charCodeAt(0) + ';' + }). + replace(//g, '>') + }, + currency: function(amount, symbol, fractionSize) { + return (symbol || "\uFFE5") + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2) + }, + number: numberFormat +} +/* + 'yyyy': 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010) + 'yy': 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) + 'y': 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199) + 'MMMM': Month in year (January-December) + 'MMM': Month in year (Jan-Dec) + 'MM': Month in year, padded (01-12) + 'M': Month in year (1-12) + 'dd': Day in month, padded (01-31) + 'd': Day in month (1-31) + 'EEEE': Day in Week,(Sunday-Saturday) + 'EEE': Day in Week, (Sun-Sat) + 'HH': Hour in day, padded (00-23) + 'H': Hour in day (0-23) + 'hh': Hour in am/pm, padded (01-12) + 'h': Hour in am/pm, (1-12) + 'mm': Minute in hour, padded (00-59) + 'm': Minute in hour (0-59) + 'ss': Second in minute, padded (00-59) + 's': Second in minute (0-59) + 'a': am/pm marker + 'Z': 4 digit (+sign) representation of the timezone offset (-1200-+1200) + format string can also be one of the following predefined localizable formats: + + 'medium': equivalent to 'MMM d, y h:mm:ss a' for en_US locale (e.g. Sep 3, 2010 12:05:08 pm) + 'short': equivalent to 'M/d/yy h:mm a' for en_US locale (e.g. 9/3/10 12:05 pm) + 'fullDate': equivalent to 'EEEE, MMMM d,y' for en_US locale (e.g. Friday, September 3, 2010) + 'longDate': equivalent to 'MMMM d, y' for en_US locale (e.g. September 3, 2010 + 'mediumDate': equivalent to 'MMM d, y' for en_US locale (e.g. Sep 3, 2010) + 'shortDate': equivalent to 'M/d/yy' for en_US locale (e.g. 9/3/10) + 'mediumTime': equivalent to 'h:mm:ss a' for en_US locale (e.g. 12:05:08 pm) + 'shortTime': equivalent to 'h:mm a' for en_US locale (e.g. 12:05 pm) + */ +new function() {// jshint ignore:line + function toInt(str) { + return parseInt(str, 10) || 0 + } + + function padNumber(num, digits, trim) { + var neg = "" + if (num < 0) { + neg = '-' + num = -num + } + num = "" + num + while (num.length < digits) + num = "0" + num + if (trim) + num = num.substr(num.length - digits) + return neg + num + } + + function dateGetter(name, size, offset, trim) { + return function(date) { + var value = date["get" + name]() + if (offset > 0 || value > -offset) + value += offset + if (value === 0 && offset === -12) { + value = 12 + } + return padNumber(value, size, trim) + } + } + + function dateStrGetter(name, shortForm) { + return function(date, formats) { + var value = date["get" + name]() + var get = (shortForm ? ("SHORT" + name) : name).toUpperCase() + return formats[get][value] + } + } + + function timeZoneGetter(date) { + var zone = -1 * date.getTimezoneOffset() + var paddedZone = (zone >= 0) ? "+" : "" + paddedZone += padNumber(Math[zone > 0 ? "floor" : "ceil"](zone / 60), 2) + padNumber(Math.abs(zone % 60), 2) + return paddedZone + } + //å–得上åˆä¸‹åˆ + + function ampmGetter(date, formats) { + return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1] + } + var DATE_FORMATS = { + yyyy: dateGetter("FullYear", 4), + yy: dateGetter("FullYear", 2, 0, true), + y: dateGetter("FullYear", 1), + MMMM: dateStrGetter("Month"), + MMM: dateStrGetter("Month", true), + MM: dateGetter("Month", 2, 1), + M: dateGetter("Month", 1, 1), + dd: dateGetter("Date", 2), + d: dateGetter("Date", 1), + HH: dateGetter("Hours", 2), + H: dateGetter("Hours", 1), + hh: dateGetter("Hours", 2, -12), + h: dateGetter("Hours", 1, -12), + mm: dateGetter("Minutes", 2), + m: dateGetter("Minutes", 1), + ss: dateGetter("Seconds", 2), + s: dateGetter("Seconds", 1), + sss: dateGetter("Milliseconds", 3), + EEEE: dateStrGetter("Day"), + EEE: dateStrGetter("Day", true), + a: ampmGetter, + Z: timeZoneGetter + } + var rdateFormat = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/ + var raspnetjson = /^\/Date\((\d+)\)\/$/ + filters.date = function(date, format) { + var locate = filters.date.locate, + text = "", + parts = [], + fn, match + format = format || "mediumDate" + format = locate[format] || format + if (typeof date === "string") { + if (/^\d+$/.test(date)) { + date = toInt(date) + } else if (raspnetjson.test(date)) { + date = +RegExp.$1 + } else { + var trimDate = date.trim() + var dateArray = [0, 0, 0, 0, 0, 0, 0] + var oDate = new Date(0) + //å–得年月日 + trimDate = trimDate.replace(/^(\d+)\D(\d+)\D(\d+)/, function(_, a, b, c) { + var array = c.length === 4 ? [c, a, b] : [a, b, c] + dateArray[0] = toInt(array[0]) //å¹´ + dateArray[1] = toInt(array[1]) - 1 //月 + dateArray[2] = toInt(array[2]) //æ—¥ + return "" + }) + var dateSetter = oDate.setFullYear + var timeSetter = oDate.setHours + trimDate = trimDate.replace(/[T\s](\d+):(\d+):?(\d+)?\.?(\d)?/, function(_, a, b, c, d) { + dateArray[3] = toInt(a) //å°æ—¶ + dateArray[4] = toInt(b) //分钟 + dateArray[5] = toInt(c) //秒 + if (d) { //毫秒 + dateArray[6] = Math.round(parseFloat("0." + d) * 1000) + } + return "" + }) + var tzHour = 0 + var tzMin = 0 + trimDate = trimDate.replace(/Z|([+-])(\d\d):?(\d\d)/, function(z, symbol, c, d) { + dateSetter = oDate.setUTCFullYear + timeSetter = oDate.setUTCHours + if (symbol) { + tzHour = toInt(symbol + c) + tzMin = toInt(symbol + d) + } + return "" + }) + + dateArray[3] -= tzHour + dateArray[4] -= tzMin + dateSetter.apply(oDate, dateArray.slice(0, 3)) + timeSetter.apply(oDate, dateArray.slice(3)) + date = oDate + } + } + if (typeof date === "number") { + date = new Date(date) + } + if (avalon.type(date) !== "date") { + return + } + while (format) { + match = rdateFormat.exec(format) + if (match) { + parts = parts.concat(match.slice(1)) + format = parts.pop() + } else { + parts.push(format) + format = null + } + } + parts.forEach(function(value) { + fn = DATE_FORMATS[value] + text += fn ? fn(date, locate) : value.replace(/(^'|'$)/g, "").replace(/''/g, "'") + }) + return text + } + var locate = { + AMPMS: { + 0: "上åˆ", + 1: "下åˆ" + }, + DAY: { + 0: "星期日", + 1: "星期一", + 2: "星期二", + 3: "星期三", + 4: "星期四", + 5: "星期五", + 6: "星期六" + }, + MONTH: { + 0: "1月", + 1: "2月", + 2: "3月", + 3: "4月", + 4: "5月", + 5: "6月", + 6: "7月", + 7: "8月", + 8: "9月", + 9: "10月", + 10: "11月", + 11: "12月" + }, + SHORTDAY: { + "0": "周日", + "1": "周一", + "2": "周二", + "3": "周三", + "4": "周四", + "5": "周五", + "6": "周六" + }, + fullDate: "yå¹´M月dæ—¥EEEE", + longDate: "yå¹´M月dæ—¥", + medium: "yyyy-M-d H:mm:ss", + mediumDate: "yyyy-M-d", + mediumTime: "H:mm:ss", + "short": "yy-M-d ah:mm", + shortDate: "yy-M-d", + shortTime: "ah:mm" + } + locate.SHORTMONTH = locate.MONTH + filters.date.locate = locate +}// jshint ignore:line +/********************************************************************* + * AMD加载器 * + **********************************************************************/ +//https://www.devbridge.com/articles/understanding-amd-requirejs/ +//http://maxogden.com/nested-dependencies.html +var modules = avalon.modules = { + "domReady!": { + exports: avalon, + state: 3 + }, + "avalon": { + exports: avalon, + state: 4 + } +} +//Object(modules[id]).state拥有如下值 +// undefined 没有定义 +// 1(send) å·²ç»å‘出请求 +// 2(loading) å·²ç»è¢«æ‰§è¡Œä½†è¿˜æ²¡æœ‰æ‰§è¡Œå®Œæˆï¼Œåœ¨è¿™ä¸ªé˜¶æ®µdefine方法会被执行 +// 3(loaded) 执行完毕,通过onload/onreadystatechange回调判定,在这个阶段checkDeps方法会执行 +// 4(execute) å…¶ä¾èµ–也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行 +modules.exports = modules.avalon + +new function () {// jshint ignore:line + var loadings = [] //正在加载中的模å—列表 + var factorys = [] //放置define方法的factory函数 + var rjsext = /\.js$/i + function makeRequest(name, config) { +//1. 去掉资æºå‰ç¼€ + var res = "js" + name = name.replace(/^(\w+)\!/, function (a, b) { + res = b + return "" + }) + if (res === "ready") { + log("debug: ready!å·²ç»è¢«åºŸå¼ƒï¼Œè¯·ä½¿ç”¨domReady!") + res = "domReady" + } +//2. 去掉querystring, hash + var query = "" + name = name.replace(rquery, function (a) { + query = a + return "" + }) + //3. 去掉扩展å + var suffix = "." + res + var ext = /js|css/.test(suffix) ? suffix : "" + name = name.replace(/\.[a-z0-9]+$/g, function (a) { + if (a === suffix) { + ext = a + return "" + } else { + return a + } + }) + var req = avalon.mix({ + query: query, + ext: ext, + res: res, + name: name, + toUrl: toUrl + }, config) + req.toUrl(name) + return req + } + + function fireRequest(req) { + var name = req.name + var res = req.res + //1. 如果该模å—å·²ç»å‘出请求,直接返回 + var module = modules[name] + var urlNoQuery = name && req.urlNoQuery + if (module && module.state >= 1) { + return name + } + module = modules[urlNoQuery] + if (module && module.state >= 3) { + innerRequire(module.deps || [], module.factory, urlNoQuery) + return urlNoQuery + } + if (name && !module) { + module = modules[urlNoQuery] = { + id: urlNoQuery, + state: 1 //send + } + var wrap = function (obj) { + resources[res] = obj + obj.load(name, req, function (a) { + if (arguments.length && a !== void 0) { + module.exports = a + } + module.state = 4 + checkDeps() + }) + } + + if (!resources[res]) { + innerRequire([res], wrap) + } else { + wrap(resources[res]) + } + } + return name ? urlNoQuery : res + "!" + } + +//核心API之一 require + var requireQueue = [] + var isUserFirstRequire = false + innerRequire = avalon.require = function (array, factory, parentUrl, defineConfig) { + if (!isUserFirstRequire) { + requireQueue.push(avalon.slice(arguments)) + if (arguments.length <= 2) { + isUserFirstRequire = true + var queue = requireQueue.splice(0, requireQueue.length), args + while (args = queue.shift()) { + innerRequire.apply(null, args) + } + } + return + } + + if (!Array.isArray(array)) { + avalon.error("require方法的第一个å‚数应为数组 " + array) + } + var deps = [] // 放置所有ä¾èµ–项的完整路径 + var uniq = {} + var id = parentUrl || "callback" + setTimeout("1")// jshint ignore:line + defineConfig = defineConfig || {} + defineConfig.baseUrl = kernel.baseUrl + var isBuilt = !!defineConfig.built + if (parentUrl) { + defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf("/")) + defineConfig.mapUrl = parentUrl.replace(rjsext, "") + } + if (isBuilt) { + var req = makeRequest(defineConfig.defineName, defineConfig) + id = req.urlNoQuery + } else { + array.forEach(function (name) { + var req = makeRequest(name, defineConfig) + var url = fireRequest(req) //加载资æºï¼Œå¹¶è¿”回该资æºçš„å®Œæ•´åœ°å€ + if (url) { + if (!uniq[url]) { + deps.push(url) + uniq[url] = "å¸å¾’正美" //åŽ»é‡ + } + } + }) + } + + var module = modules[id] + if (!module || module.state !== 4) { + modules[id] = { + id: id, + deps: isBuilt ? array.concat() : deps, + factory: factory || noop, + state: 3 + } + } + if (!module) { + //如果此模å—是定义在å¦ä¸€ä¸ªJS文件中, 那必须等该文件加载完毕, æ‰èƒ½æ”¾åˆ°æ£€æµ‹åˆ—队中 + loadings.push(id) + } + checkDeps() + } + +//核心API之二 require + innerRequire.define = function (name, deps, factory) { //模å—å,ä¾èµ–列表,模å—本身 + if (typeof name !== "string") { + factory = deps + deps = name + name = "anonymous" + } + if (!Array.isArray(deps)) { + factory = deps + deps = [] + } + var config = { + built: !isUserFirstRequire, //用r.js打包åŽ,所有define会放到requirejsä¹‹å‰ + defineName: name + } + var args = [deps, factory, config] + factory.require = function (url) { + args.splice(2, 0, url) + if (modules[url]) { + modules[url].state = 3 //loaded + var isCycle = false + try { + isCycle = checkCycle(modules[url].deps, url) + } catch (e) { + } + if (isCycle) { + avalon.error(url + "模å—与之å‰çš„模å—存在循环ä¾èµ–,请ä¸è¦ç›´æŽ¥ç”¨script标签引入" + url + "模å—") + } + } + delete factory.require //释放内存 + innerRequire.apply(null, args) //0,1,2 --> 1,2,0 + } +//æ ¹æ®æ ‡å‡†,所有éµå¾ªW3C标准的æµè§ˆå™¨,script标签会按标签的出现顺åºæ‰§è¡Œã€‚ +//è€çš„æµè§ˆå™¨ä¸­ï¼ŒåŠ è½½ä¹Ÿæ˜¯æŒ‰é¡ºåºçš„:一个文件下载完æˆåŽï¼Œæ‰å¼€å§‹ä¸‹è½½ä¸‹ä¸€ä¸ªæ–‡ä»¶ã€‚ +//较新的æµè§ˆå™¨ä¸­ï¼ˆIE8+ ã€FireFox3.5+ ã€Chrome4+ ã€Safari4+),为了å‡å°è¯·æ±‚时间以优化体验, +//下载å¯ä»¥æ˜¯å¹¶è¡Œçš„,但是执行顺åºè¿˜æ˜¯æŒ‰ç…§æ ‡ç­¾å‡ºçŽ°çš„顺åºã€‚ +//但如果script标签是动æ€æ’入的, 就未必按照先请求先执行的原则了,目测åªæœ‰firefoxéµå®ˆ +//唯一比较一致的是,IE10+åŠå…¶ä»–标准æµè§ˆå™¨,一旦开始解æžè„šæœ¬, 就会一直堵在那里,直接脚本解æžå®Œæ¯• +//亦å³ï¼Œå…ˆè¿›å…¥loading阶段的script标签(模å—)必然会先进入loaded阶段 + var url = config.built ? "unknown" : getCurrentScript() + if (url) { + var module = modules[url] + if (module) { + module.state = 2 + } + factory.require(url) + } else {//åˆå¹¶å‰åŽçš„safari,åˆå¹¶åŽçš„IE6-9走此分支 + factorys.push(factory) + } + } +//核心API之三 require.config(settings) + innerRequire.config = kernel + //核心API之四 define.amd 标识其符åˆAMD规范 + innerRequire.define.amd = modules + + //==========================对用户é…置项进行å†åŠ å·¥========================== + var allpaths = kernel["orig.paths"] = {} + var allmaps = kernel["orig.map"] = {} + var allpackages = kernel["packages"] = [] + var allargs = kernel["orig.args"] = {} + avalon.mix(plugins, { + paths: function (hash) { + avalon.mix(allpaths, hash) + kernel.paths = makeIndexArray(allpaths) + }, + map: function (hash) { + avalon.mix(allmaps, hash) + var list = makeIndexArray(allmaps, 1, 1) + avalon.each(list, function (_, item) { + item.val = makeIndexArray(item.val) + }) + kernel.map = list + }, + packages: function (array) { + array = array.concat(allpackages) + var uniq = {} + var ret = [] + for (var i = 0, pkg; pkg = array[i++]; ) { + pkg = typeof pkg === "string" ? {name: pkg} : pkg + var name = pkg.name + if (!uniq[name]) { + var url = joinPath(pkg.location || name, pkg.main || "main") + url = url.replace(rjsext, "") + ret.push(pkg) + uniq[name] = pkg.location = url + pkg.reg = makeMatcher(name) + } + } + kernel.packages = ret.sort() + }, + urlArgs: function (hash) { + if (typeof hash === "string") { + hash = {"*": hash} + } + avalon.mix(allargs, hash) + kernel.urlArgs = makeIndexArray(allargs, 1) + }, + baseUrl: function (url) { + if (!isAbsUrl(url)) { + var baseElement = head.getElementsByTagName("base")[0] + if (baseElement) { + head.removeChild(baseElement) + } + var node = DOC.createElement("a") + node.href = url + url = getFullUrl(node, "href") + if (baseElement) { + head.insertBefore(baseElement, head.firstChild) + } + } + if (url.length > 3) + kernel.baseUrl = url + }, + shim: function (obj) { + for (var i in obj) { + var value = obj[i] + if (Array.isArray(value)) { + value = obj[i] = { + deps: value + } + } + if (!value.exportsFn && (value.exports || value.init)) { + value.exportsFn = makeExports(value) + } + } + kernel.shim = obj + } + + }) + + + //==============================内部方法================================= + function checkCycle(deps, nick) { + //检测是å¦å­˜åœ¨å¾ªçŽ¯ä¾èµ– + for (var i = 0, id; id = deps[i++]; ) { + if (modules[id].state !== 4 && + (id === nick || checkCycle(modules[id].deps, nick))) { + return true + } + } + } + + function checkFail(node, onError, fuckIE) { + var id = trimQuery(node.src) //检测是å¦æ­»é“¾ + node.onload = node.onreadystatechange = node.onerror = null + if (onError || (fuckIE && modules[id] && !modules[id].state)) { + setTimeout(function () { + head.removeChild(node) + node = null // 处ç†æ—§å¼IE下的循环引用问题 + }) + log("debug: 加载 " + id + " 失败" + onError + " " + (!modules[id].state)) + } else { + return true + } + } + + function checkDeps() { + //检测此JS模å—çš„ä¾èµ–是å¦éƒ½å·²å®‰è£…完毕,是则安装自身 + loop: for (var i = loadings.length, id; id = loadings[--i]; ) { + var obj = modules[id], + deps = obj.deps + if (!deps) + continue + for (var j = 0, key; key = deps[j]; j++) { + if (Object(modules[key]).state !== 4) { + continue loop + } + } + //如果deps是空对象或者其ä¾èµ–的模å—的状æ€éƒ½æ˜¯2 + if (obj.state !== 4) { + loadings.splice(i, 1) //必须先移除å†å®‰è£…,防止在IE下DOM树建完åŽæ‰‹åŠ¨åˆ·æ–°é¡µé¢ï¼Œä¼šå¤šæ¬¡æ‰§è¡Œå®ƒ + fireFactory(obj.id, obj.deps, obj.factory) + checkDeps() //如果æˆåŠŸ,则å†æ‰§è¡Œä¸€æ¬¡,以防有些模å—就差本模å—没有安装好 + } + } + } + + var rreadyState = /complete|loaded/ + function loadJS(url, id, callback) { + //通过scriptèŠ‚ç‚¹åŠ è½½ç›®æ ‡æ¨¡å— + var node = DOC.createElement("script") + node.className = subscribers //让getCurrentScriptåªå¤„ç†ç±»å为subscribersçš„script节点 + var supportLoad = "onload" in node + var onEvent = supportLoad ? "onload" : "onreadystatechange" + function onload() { + var factory = factorys.pop() + factory && factory.require(id) + if (callback) { + callback() + } + if (checkFail(node, false, !supportLoad)) { + log("debug: å·²æˆåŠŸåŠ è½½ " + url) + id && loadings.push(id) + checkDeps() + } + } + var index = 0, loadID + node[onEvent] = supportLoad ? onload : function () { + if (rreadyState.test(node.readyState)) { + ++index + if (index === 1) { + loadID = setTimeout(onload, 500) + } else { + clearTimeout(loadID) + onload() + } + } + } + node.onerror = function () { + checkFail(node, true) + } + + head.insertBefore(node, head.firstChild) //chrome下第二个å‚æ•°ä¸èƒ½ä¸ºnull + node.src = url //æ’入到head的第一个节点å‰ï¼Œé˜²æ­¢IE6下head标签没闭åˆå‰ä½¿ç”¨appendChild抛错 + log("debug: 正准备加载 " + url) //æ›´é‡è¦çš„是IE6下å¯ä»¥æ”¶çª„getCurrentScript的寻找范围 + } + + var resources = innerRequire.plugins = { + //三大常用资æºæ’件 js!, css!, text!, ready! + ready: { + load: noop + }, + js: { + load: function (name, req, onLoad) { + var url = req.url + var id = req.urlNoQuery + var shim = kernel.shim[name.replace(rjsext, "")] + if (shim) { //shim机制 + innerRequire(shim.deps || [], function () { + var args = avalon.slice(arguments) + loadJS(url, id, function () { + onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0) + }) + }) + } else { + loadJS(url, id) + } + } + }, + css: { + load: function (name, req, onLoad) { + var url = req.url + var node = DOC.createElement("link") + node.rel = "stylesheet" + node.href = url + head.insertBefore(node, head.firstChild) + log("debug: å·²æˆåŠŸåŠ è½½ " + url) + onLoad() + } + }, + text: { + load: function (name, req, onLoad) { + var url = req.url + var xhr = getXHR() + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + var status = xhr.status; + if (status > 399 && status < 600) { + avalon.error(url + " 对应资æºä¸å­˜åœ¨æˆ–æ²¡æœ‰å¼€å¯ CORS") + } else { + log("debug: å·²æˆåŠŸåŠ è½½ " + url) + onLoad(xhr.responseText) + } + } + } + var time = "_=" + (new Date() - 0) + var _url = url.indexOf("?") === -1 ? url + "?" + time : url + "&" + time + xhr.open("GET", _url, true) + if ("withCredentials" in xhr) {//这是处ç†è·¨åŸŸ + xhr.withCredentials = true + } + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")//告诉åŽç«¯è¿™æ˜¯AJAX请求 + xhr.send() + log("debug: 正准备加载 " + url) + } + } + } + innerRequire.checkDeps = checkDeps + + var rquery = /(\?[^#]*)$/ + function trimQuery(url) { + return (url || "").replace(rquery, "") + } + + function isAbsUrl(path) { + //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative + return /^(?:[a-z]+:)?\/\//i.test(String(path)) + } + + function getFullUrl(node, src) { + return"1"[0] ? node[src] : node.getAttribute(src, 4) + } + + function getCurrentScript() { + // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js + var stack + try { + a.b.c() //强制报错,以便æ•èŽ·e.stack + } catch (e) { //safari5çš„sourceURL,firefoxçš„fileName,它们的效果与e.stackä¸ä¸€æ · + stack = e.stack + if (!stack && window.opera) { + //opera 9没有e.stack,但有e.Backtrace,但ä¸èƒ½ç›´æŽ¥å–å¾—,需è¦å¯¹eå¯¹è±¡è½¬å­—ç¬¦ä¸²è¿›è¡ŒæŠ½å– + stack = (String(e).match(/of linked script \S+/g) || []).join(" ") + } + } + if (stack) { + /**e.stack最åŽä¸€è¡Œåœ¨æ‰€æœ‰æ”¯æŒçš„æµè§ˆå™¨å¤§è‡´å¦‚下: + *chrome23: + * at http://113.93.50.63/data.js:4:1 + *firefox17: + *@http://113.93.50.63/query.js:4 + *opera12:http://www.oldapps.com/opera.php?system=Windows_XP + *@http://113.93.50.63/data.js:4 + *IE10: + * at Global code (http://113.93.50.63/data.js:4:1) + * //firefox4+ å¯ä»¥ç”¨document.currentScript + */ + stack = stack.split(/[@ ]/g).pop() //å–得最åŽä¸€è¡Œ,最åŽä¸€ä¸ªç©ºæ ¼æˆ–@之åŽçš„部分 + stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉æ¢è¡Œç¬¦ + return trimQuery(stack.replace(/(:\d+)?:\d+$/i, "")) //去掉行å·ä¸Žæˆ–许存在的出错字符起始ä½ç½® + } + var nodes = head.getElementsByTagName("script") //åªåœ¨head标签中寻找 + for (var i = nodes.length, node; node = nodes[--i]; ) { + if (node.className === subscribers && node.readyState === "interactive") { + var url = getFullUrl(node, "src") + return node.className = trimQuery(url) + } + } + } + + var rcallback = /^callback\d+$/ + function fireFactory(id, deps, factory) { + var module = Object(modules[id]) + module.state = 4 + for (var i = 0, array = [], d; d = deps[i++]; ) { + if (d === "exports") { + var obj = module.exports || (module.exports = {}) + array.push(obj) + } else { + array.push(modules[d].exports) + } + } + try { + var ret = factory.apply(window, array) + } catch (e) { + log("执行[" + id + "]模å—çš„factory抛错: ", e) + } + if (ret !== void 0) { + module.exports = ret + } + if (rcallback.test(id)) { + delete modules[id] + } + delete module.factory + return ret + } + function toUrl(id) { + if (id.indexOf(this.res + "!") === 0) { + id = id.slice(this.res.length + 1) //处ç†define("css!style",[], function(){})的情况 + } + var url = id + //1. 是å¦å‘½ä¸­pathsé…置项 + var usePath = 0 + var baseUrl = this.baseUrl + var rootUrl = this.parentUrl || baseUrl + eachIndexArray(id, kernel.paths, function (value, key) { + url = url.replace(key, value) + usePath = 1 + }) + //2. 是å¦å‘½ä¸­packagesé…置项 + if (!usePath) { + eachIndexArray(id, kernel.packages, function (value, key, item) { + url = url.replace(item.name, item.location) + }) + } + //3. 是å¦å‘½ä¸­mapé…置项 + if (this.mapUrl) { + eachIndexArray(this.mapUrl, kernel.map, function (array) { + eachIndexArray(url, array, function (mdValue, mdKey) { + url = url.replace(mdKey, mdValue) + rootUrl = baseUrl + }) + }) + } + var ext = this.ext + if (ext && usePath && url.slice(-ext.length) === ext) { + url = url.slice(0, -ext.length) + } + //4. 转æ¢ä¸ºç»å¯¹è·¯å¾„ + if (!isAbsUrl(url)) { + rootUrl = this.built || /^\w/.test(url) ? baseUrl : rootUrl + url = joinPath(rootUrl, url) + } + //5. 还原扩展å,query + var urlNoQuery = url + ext + url = urlNoQuery + this.query + //6. 处ç†urlArgs + eachIndexArray(id, kernel.urlArgs, function (value) { + url += (url.indexOf("?") === -1 ? "?" : "&") + value; + }) + this.url = url + return this.urlNoQuery = urlNoQuery + } + + function makeIndexArray(hash, useStar, part) { + //创建一个ç»è¿‡ç‰¹æ®Šç®—法排好åºçš„数组 + var index = hash2array(hash, useStar, part) + index.sort(descSorterByName) + return index + } + + function makeMatcher(prefix) { + return new RegExp('^' + prefix + '(/|$)') + } + + function makeExports(value) { + return function () { + var ret + if (value.init) { + ret = value.init.apply(window, arguments) + } + return ret || (value.exports && getGlobal(value.exports)) + } + } + + + function hash2array(hash, useStar, part) { + var array = []; + for (var key in hash) { + if (ohasOwn.call(hash, key)) { + var item = { + name: key, + val: hash[key] + } + array.push(item) + item.reg = key === "*" && useStar ? /^/ : makeMatcher(key) + if (part && key !== "*") { + item.reg = new RegExp('\/' + key.replace(/^\//, "") + '(/|$)') + } + } + } + return array + } + + function eachIndexArray(moduleID, array, matcher) { + array = array || [] + for (var i = 0, el; el = array[i++]; ) { + if (el.reg.test(moduleID)) { + matcher(el.val, el.name, el) + return false + } + } + } + // æ ¹æ®å…ƒç´ çš„name项进行数组字符数逆åºçš„排åºå‡½æ•° + function descSorterByName(a, b) { + var aaa = a.name + var bbb = b.name + if (bbb === "*") { + return -1 + } + if (aaa === "*") { + return 1 + } + return bbb.length - aaa.length + } + + var rdeuce = /\/\w+\/\.\./ + function joinPath(a, b) { + if (a.charAt(a.length - 1) !== "/") { + a += "/" + } + if (b.slice(0, 2) === "./") { //相对于兄弟路径 + return a + b.slice(2) + } + if (b.slice(0, 2) === "..") { //相对于父路径 + a += b + while (rdeuce.test(a)) { + a = a.replace(rdeuce, "") + } + return a + } + if (b.slice(0, 1) === "/") { + return a + b.slice(1) + } + return a + b + } + + function getGlobal(value) { + if (!value) { + return value + } + var g = window + value.split(".").forEach(function (part) { + g = g[part] + }) + return g + } + + var mainNode = DOC.scripts[DOC.scripts.length - 1] + var dataMain = mainNode.getAttribute("data-main") + if (dataMain) { + plugins.baseUrl(dataMain) + var href = kernel.baseUrl + kernel.baseUrl = href.slice(0, href.lastIndexOf("/") + 1) + loadJS(href.replace(rjsext, "") + ".js") + } else { + var loaderUrl = trimQuery(getFullUrl(mainNode, "src")) + kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1) + } +}// jshint ignore:line + +/********************************************************************* + * DOMReady * + **********************************************************************/ + +var readyList = [], isReady +var fireReady = function(fn) { + isReady = true + if (innerRequire) { + modules["domReady!"].state = 4 + innerRequire.checkDeps() + } + while(fn = readyList.shift()){ + fn(avalon) + } +} + +function doScrollCheck() { + try { //IE下通过doScrollCheck检测DOM树是å¦å»ºå®Œ + root.doScroll("left") + fireReady() + } catch (e) { + setTimeout(doScrollCheck) + } +} + +if (DOC.readyState === "complete") { + setTimeout(fireReady) //如果在domReady之外加载 +} else if (W3C) { + DOC.addEventListener("DOMContentLoaded", fireReady) +} else { + DOC.attachEvent("onreadystatechange", function() { + if (DOC.readyState === "complete") { + fireReady() + } + }) + try { + var isTop = window.frameElement === null + } catch (e) { + } + if (root.doScroll && isTop && window.external) {//fix IE iframe BUG + doScrollCheck() + } +} +avalon.bind(window, "load", fireReady) + +avalon.ready = function(fn) { + if (!isReady) { + readyList.push(fn) + } else { + fn(avalon) + } +} + +avalon.config({ + loader: true +}) + +avalon.ready(function() { + avalon.scan(DOC.body) +}) + +// Register as a named AMD module, since avalon can be concatenated with other +// files that may use define, but not via a proper concatenation script that +// understands anonymous AMD modules. A named AMD is safest and most robust +// way to register. Lowercase avalon is used because AMD module names are +// derived from file names, and Avalon is normally delivered in a lowercase +// file name. Do this after creating the global so that if an AMD module wants +// to call noConflict to hide this version of avalon, it will work. + +// Note that for maximum portability, libraries that are not avalon should +// declare themselves as anonymous modules, and avoid setting a global if an +// AMD loader is present. avalon is a special case. For more information, see +// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon + if (typeof define === "function" && define.amd) { + define("avalon", [], function() { + return avalon + }) + } +// Map over avalon in case of overwrite + var _avalon = window.avalon + avalon.noConflict = function(deep) { + if (deep && window.avalon === avalon) { + window.avalon = _avalon + } + return avalon + } +// Expose avalon identifiers, even in AMD +// and CommonJS for browser emulators + if (noGlobal === void 0) { + window.avalon = avalon + } + return avalon + })); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/avalon/avalon.modern.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/avalon/avalon.modern.js index 048b4241..7c37393f 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/avalon/avalon.modern.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/avalon/avalon.modern.js @@ -1,4935 +1,4935 @@ -/*================================================== - Copyright (c) 2013-2015 å¸å¾’正美 and other contributors - http://www.cnblogs.com/rubylouvre/ - https://github.com/RubyLouvre - http://weibo.com/jslouvre/ - - Released under the MIT license - avalon.modern.js 1.43 built in 2015.5.21 - support IE10+ and other browsers - ==================================================*/ -(function (global, factory) { - - if (typeof module === "object" && typeof module.exports === "object") { - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get avalon. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var avalon = require("avalon")(window); - module.exports = global.document ? factory(global, true) : function (w) { - if (!w.document) { - throw new Error("Avalon requires a window with a document") - } - return factory(w) - } - } else { - factory(global) - } - -// Pass this if window is not defined yet -}(typeof window !== "undefined" ? window : this, function (window, noGlobal) { - - /********************************************************************* - * 全局å˜é‡åŠæ–¹æ³• * - **********************************************************************/ - var expose = Date.now() -//http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function - var DOC = window.document - var head = DOC.head //HEAD元素 - head.insertAdjacentHTML("afterBegin", '') - var ifGroup = head.firstChild - - function log() { - if (avalon.config.debug) { -// http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log - console.log.apply(console, arguments) - } - } - - /** - * Creates a new object without a prototype. This object is useful for lookup without having to - * guard against prototypically inherited properties via hasOwnProperty. - * - * Related micro-benchmarks: - * - http://jsperf.com/object-create2 - * - http://jsperf.com/proto-map-lookup/2 - * - http://jsperf.com/for-in-vs-object-keys2 - */ - function createMap() { - return Object.create(null) - } - - var subscribers = "$" + expose - var otherRequire = window.require - var otherDefine = window.define - var innerRequire - var stopRepeatAssign = false - var rword = /[^, ]+/g //切割字符串为一个个å°å—,以空格或豆å·åˆ†å¼€å®ƒä»¬ï¼Œç»“åˆreplace实现字符串的forEach - var rcomplexType = /^(?:object|array)$/ - var rsvg = /^\[object SVG\w*Element\]$/ - var rwindow = /^\[object (?:Window|DOMWindow|global)\]$/ - var oproto = Object.prototype - var ohasOwn = oproto.hasOwnProperty - var serialize = oproto.toString - var ap = Array.prototype - var aslice = ap.slice - var Registry = {} //将函数æ›å…‰åˆ°æ­¤å¯¹è±¡ä¸Šï¼Œæ–¹ä¾¿è®¿é—®å™¨æ”¶é›†ä¾èµ– - var W3C = window.dispatchEvent - var root = DOC.documentElement - var hyperspace = DOC.createDocumentFragment() - var cinerator = DOC.createElement("div") - var class2type = {} - "Boolean Number String Function Array Date RegExp Object Error".replace(rword, function (name) { - class2type["[object " + name + "]"] = name.toLowerCase() - }) - - - function noop() { - } - - - function oneObject(array, val) { - if (typeof array === "string") { - array = array.match(rword) || [] - } - var result = {}, - value = val !== void 0 ? val : 1 - for (var i = 0, n = array.length; i < n; i++) { - result[array[i]] = value - } - return result - } - -//生æˆUUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript - var generateID = function (prefix) { - prefix = prefix || "avalon" - return String(Math.random() + Math.random()).replace(/\d\.\d{4}/, prefix) - } - - function IE() { - if (window.VBArray) { - var mode = document.documentMode - return mode ? mode : window.XMLHttpRequest ? 7 : 6 - } else { - return 0 - } - } - - var IEVersion = IE() - - avalon = function (el) { //创建jQueryå¼çš„æ— new 实例化结构 - return new avalon.init(el) - } - - /*视æµè§ˆå™¨æƒ…况采用最快的异步回调*/ - avalon.nextTick = new function () {// jshint ignore:line - var tickImmediate = window.setImmediate - var tickObserver = window.MutationObserver - var tickPost = W3C && window.postMessage - if (tickImmediate) { - return tickImmediate.bind(window) - } - - var queue = [] - - function callback() { - var n = queue.length - for (var i = 0; i < n; i++) { - queue[i]() - } - queue = queue.slice(n) - } - - if (tickObserver) { - var node = document.createTextNode("avalon") - new tickObserver(callback).observe(node, {characterData: true})// jshint ignore:line - return function (fn) { - queue.push(fn) - node.data = Math.random() - } - } - - if (tickPost) { - window.addEventListener("message", function (e) { - var source = e.source - if ((source === window || source === null) && e.data === "process-tick") { - e.stopPropagation() - callback() - } - }) - - return function (fn) { - queue.push(fn) - window.postMessage('process-tick', '*') - } - } - - return function (fn) { - setTimeout(fn, 0) - } - }// jshint ignore:line - /********************************************************************* - * avalonçš„é™æ€æ–¹æ³•å®šä¹‰åŒº * - **********************************************************************/ - avalon.init = function (el) { - this[0] = this.element = el - } - avalon.fn = avalon.prototype = avalon.init.prototype - - avalon.type = function (obj) { //å–得目标的类型 - if (obj == null) { - return String(obj) - } - // 早期的webkit内核æµè§ˆå™¨å®žçŽ°äº†å·²åºŸå¼ƒçš„ecma262v4标准,å¯ä»¥å°†æ­£åˆ™å­—é¢é‡å½“作函数使用,因此typeof在判定正则时会返回function - return typeof obj === "object" || typeof obj === "function" ? - class2type[serialize.call(obj)] || "object" : - typeof obj - } - - var isFunction = function (fn) { - return serialize.call(fn) === "[object Function]" - } - - avalon.isFunction = isFunction - - avalon.isWindow = function (obj) { - return rwindow.test(serialize.call(obj)) - } - - /*判定是å¦æ˜¯ä¸€ä¸ªæœ´ç´ çš„javascript对象(Object),ä¸æ˜¯DOM对象,ä¸æ˜¯BOM对象,ä¸æ˜¯è‡ªå®šä¹‰ç±»çš„实例*/ - - avalon.isPlainObject = function (obj) { - // 简å•çš„ typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通ä¸è¿‡ - return serialize.call(obj) === "[object Object]" && Object.getPrototypeOf(obj) === oproto - } - -//与jQuery.extend方法,å¯ç”¨äºŽæµ…æ‹·è´ï¼Œæ·±æ‹·è´ - avalon.mix = avalon.fn.mix = function () { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false - - // 如果第一个å‚数为布尔,判定是å¦æ·±æ‹·è´ - if (typeof target === "boolean") { - deep = target - target = arguments[1] || {} - i++ - } - - //ç¡®ä¿æŽ¥å—方为一个å¤æ‚çš„æ•°æ®ç±»åž‹ - if (typeof target !== "object" && !isFunction(target)) { - target = {} - } - - //如果åªæœ‰ä¸€ä¸ªå‚数,那么新æˆå‘˜æ·»åŠ äºŽmix所在的对象上 - if (i === length) { - target = this - i-- - } - - for (; i < length; i++) { - //åªå¤„ç†éžç©ºå‚æ•° - if ((options = arguments[i]) != null) { - for (name in options) { - src = target[name] - copy = options[name] - // 防止环引用 - if (target === copy) { - continue - } - if (deep && copy && (avalon.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { - - if (copyIsArray) { - copyIsArray = false - clone = src && Array.isArray(src) ? src : [] - - } else { - clone = src && avalon.isPlainObject(src) ? src : {} - } - - target[name] = avalon.mix(deep, clone, copy) - } else if (copy !== void 0) { - target[name] = copy - } - } - } - } - return target - } - - function _number(a, len) { //用于模拟slice, splice的效果 - a = Math.floor(a) || 0 - return a < 0 ? Math.max(len + a, 0) : Math.min(a, len); - } - - avalon.mix({ - rword: rword, - subscribers: subscribers, - version: 1.43, - ui: {}, - log: log, - slice: function (nodes, start, end) { - return aslice.call(nodes, start, end) - }, - noop: noop, - /*如果ä¸ç”¨Error对象å°è£…一下,str在控制å°ä¸‹å¯èƒ½ä¼šä¹±ç */ - error: function (str, e) { - throw new (e || Error)(str)// jshint ignore:line - }, - /*将一个以空格或逗å·éš”开的字符串或数组,转æ¢æˆä¸€ä¸ªé”®å€¼éƒ½ä¸º1的对象*/ - oneObject: oneObject, - /* avalon.range(10) - => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - avalon.range(1, 11) - => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - avalon.range(0, 30, 5) - => [0, 5, 10, 15, 20, 25] - avalon.range(0, -10, -1) - => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] - avalon.range(0) - => []*/ - range: function (start, end, step) { // 用于生æˆæ•´æ•°æ•°ç»„ - step || (step = 1) - if (end == null) { - end = start || 0 - start = 0 - } - var index = -1, - length = Math.max(0, Math.ceil((end - start) / step)), - result = new Array(length) - while (++index < length) { - result[index] = start - start += step - } - return result - }, - eventHooks: {}, - /*绑定事件*/ - bind: function (el, type, fn, phase) { - var hooks = avalon.eventHooks - var hook = hooks[type] - if (typeof hook === "object") { - type = hook.type - if (hook.deel) { - fn = hook.deel(el, type, fn, phase) - } - } - if (!fn.unbind) - el.addEventListener(type, fn, !!phase) - return fn - }, - /*å¸è½½äº‹ä»¶*/ - unbind: function (el, type, fn, phase) { - var hooks = avalon.eventHooks - var hook = hooks[type] - var callback = fn || noop - if (typeof hook === "object") { - type = hook.type - if (hook.deel) { - fn = hook.deel(el, type, fn, false) - } - } - el.removeEventListener(type, callback, !!phase) - }, - /*读写删除元素节点的样å¼*/ - css: function (node, name, value) { - if (node instanceof avalon) { - node = node[0] - } - var prop = /[_-]/.test(name) ? camelize(name) : name, fn - name = avalon.cssName(prop) || prop - if (value === void 0 || typeof value === "boolean") { //获å–æ ·å¼ - fn = cssHooks[prop + ":get"] || cssHooks["@:get"] - if (name === "background") { - name = "backgroundColor" - } - var val = fn(node, name) - return value === true ? parseFloat(val) || 0 : val - } else if (value === "") { //è¯·é™¤æ ·å¼ - node.style[name] = "" - } else { //è®¾ç½®æ ·å¼ - if (value == null || value !== value) { - return - } - if (isFinite(value) && !avalon.cssNumber[prop]) { - value += "px" - } - fn = cssHooks[prop + ":set"] || cssHooks["@:set"] - fn(node, name, value) - } - }, - /*é历数组与对象,回调的第一个å‚数为索引或键å,第二个或元素或键值*/ - each: function (obj, fn) { - if (obj) { //排除null, undefined - var i = 0 - if (isArrayLike(obj)) { - for (var n = obj.length; i < n; i++) { - if (fn(i, obj[i]) === false) - break - } - } else { - for (i in obj) { - if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) { - break - } - } - } - } - }, - //收集元素的data-{{prefix}}-*属性,并转æ¢ä¸ºå¯¹è±¡ - getWidgetData: function (elem, prefix) { - var raw = avalon(elem).data() - var result = {} - for (var i in raw) { - if (i.indexOf(prefix) === 0) { - result[i.replace(prefix, "").replace(/\w/, function (a) { - return a.toLowerCase() - })] = raw[i] - } - } - return result - }, - Array: { - /*åªæœ‰å½“å‰æ•°ç»„ä¸å­˜åœ¨æ­¤å…ƒç´ æ—¶åªæ·»åŠ å®ƒ*/ - ensure: function (target, item) { - if (target.indexOf(item) === -1) { - return target.push(item) - } - }, - /*移除数组中指定ä½ç½®çš„元素,返回布尔表示æˆåŠŸä¸Žå¦*/ - removeAt: function (target, index) { - return !!target.splice(index, 1).length - }, - /*移除数组中第一个匹é…ä¼ å‚的那个元素,返回布尔表示æˆåŠŸä¸Žå¦*/ - remove: function (target, item) { - var index = target.indexOf(item) - if (~index) - return avalon.Array.removeAt(target, index) - return false - } - } - }) - - var bindingHandlers = avalon.bindingHandlers = {} - var bindingExecutors = avalon.bindingExecutors = {} - - /*判定是å¦ç±»æ•°ç»„,如节点集åˆï¼Œçº¯æ•°ç»„,arguments与拥有éžè´Ÿæ•´æ•°çš„length属性的纯JS对象*/ - function isArrayLike(obj) { - if (obj && typeof obj === "object") { - var n = obj.length, - str = serialize.call(obj) - if (/(Array|List|Collection|Map|Arguments)\]$/.test(str)) { - return true - } else if (str === "[object Object]" && n === (n >>> 0)) { - return true //由于ecma262v5能修改对象属性的enumerable,因此ä¸èƒ½ç”¨propertyIsEnumerableæ¥åˆ¤å®šäº† - } - } - return false - } - - -// https://github.com/rsms/js-lru - var Cache = new function () {// jshint ignore:line - function LRU(maxLength) { - this.size = 0 - this.limit = maxLength - this.head = this.tail = void 0 - this._keymap = {} - } - - var p = LRU.prototype - - p.put = function (key, value) { - var entry = { - key: key, - value: value - } - this._keymap[key] = entry - if (this.tail) { - this.tail.newer = entry - entry.older = this.tail - } else { - this.head = entry - } - this.tail = entry - if (this.size === this.limit) { - this.shift() - } else { - this.size++ - } - return value - } - - p.shift = function () { - var entry = this.head - if (entry) { - this.head = this.head.newer - this.head.older = - entry.newer = - entry.older = - this._keymap[entry.key] = void 0 - } - } - p.get = function (key) { - var entry = this._keymap[key] - if (entry === void 0) - return - if (entry === this.tail) { - return entry.value - } - // HEAD--------------TAIL - // <.older .newer> - // <--- add direction -- - // A B C E - if (entry.newer) { - if (entry === this.head) { - this.head = entry.newer - } - entry.newer.older = entry.older // C <-- E. - } - if (entry.older) { - entry.older.newer = entry.newer // C. --> E - } - entry.newer = void 0 // D --x - entry.older = this.tail // D. --> E - if (this.tail) { - this.tail.newer = entry // E. <-- D - } - this.tail = entry - return entry.value - } - return LRU - }// jshint ignore:line - - /********************************************************************* - * DOM åº•å±‚è¡¥ä¸ * - **********************************************************************/ -//safari5+是把contains方法放在Element.prototype上而ä¸æ˜¯Node.prototype - if (!DOC.contains) { - Node.prototype.contains = function (arg) { - return !!(this.compareDocumentPosition(arg) & 16) - } - } - avalon.contains = function (root, el) { - try { - while ((el = el.parentNode)) - if (el === root) - return true - return false - } catch (e) { - return false - } - } - - if (window.SVGElement) { - var svgns = "http://www.w3.org/2000/svg" - var svg = DOC.createElementNS(svgns, "svg") - svg.innerHTML = '' - if (!rsvg.test(svg.firstChild)) {// #409 - /* jshint ignore:start */ - function enumerateNode(node, targetNode) { - if (node && node.childNodes) { - var nodes = node.childNodes - for (var i = 0, el; el = nodes[i++];) { - if (el.tagName) { - var svg = DOC.createElementNS(svgns, - el.tagName.toLowerCase()) - // copy attrs - ap.forEach.call(el.attributes, function (attr) { - svg.setAttribute(attr.name, attr.value) - }) - // 递归处ç†å­èŠ‚点 - enumerateNode(el, svg) - targetNode.appendChild(svg) - } - } - } - } - - /* jshint ignore:end */ - Object.defineProperties(SVGElement.prototype, { - "outerHTML": {//IE9-11,firefoxä¸æ”¯æŒSVG元素的innerHTML,outerHTML属性 - enumerable: true, - configurable: true, - get: function () { - return new XMLSerializer().serializeToString(this) - }, - set: function (html) { - var tagName = this.tagName.toLowerCase(), - par = this.parentNode, - frag = avalon.parseHTML(html) - // æ“作的svg,直接æ’å…¥ - if (tagName === "svg") { - par.insertBefore(frag, this) - // svg节点的å­èŠ‚点类似 - } else { - var newFrag = DOC.createDocumentFragment() - enumerateNode(frag, newFrag) - par.insertBefore(newFrag, this) - } - par.removeChild(this) - } - }, - "innerHTML": { - enumerable: true, - configurable: true, - get: function () { - var s = this.outerHTML - var ropen = new RegExp("<" + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', "i") - var rclose = new RegExp("<\/" + this.nodeName + ">$", "i") - return s.replace(ropen, "").replace(rclose, "") - }, - set: function (html) { - if (avalon.clearHTML) { - avalon.clearHTML(this) - var frag = avalon.parseHTML(html) - enumerateNode(frag, this) - } - } - } - }) - } - } -//========================= event binding ==================== - var eventHooks = avalon.eventHooks -//针对firefox, chrome修正mouseenter, mouseleave(chrome30+) - if (!("onmouseenter" in root)) { - avalon.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" - }, function (origType, fixType) { - eventHooks[origType] = { - type: fixType, - deel: function (elem, _, fn) { - return function (e) { - var t = e.relatedTarget - if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) { - delete e.type - e.type = origType - return fn.call(elem, e) - } - } - } - } - }) - } -//针对IE9+, w3c修正animationend - avalon.each({ - AnimationEvent: "animationend", - WebKitAnimationEvent: "webkitAnimationEnd" - }, function (construct, fixType) { - if (window[construct] && !eventHooks.animationend) { - eventHooks.animationend = { - type: fixType - } - } - }) - - if (DOC.onmousewheel === void 0) { - /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120 - firefox DOMMouseScroll detail 下3 上-3 - firefox wheel detlaY 下3 上-3 - IE9-11 wheel deltaY 下40 上-40 - chrome wheel deltaY 下100 上-100 */ - eventHooks.mousewheel = { - type: "wheel", - deel: function (elem, _, fn) { - return function (e) { - e.wheelDeltaY = e.wheelDelta = e.deltaY > 0 ? -120 : 120 - e.wheelDeltaX = 0 - Object.defineProperty(e, "type", { - value: "mousewheel" - }) - fn.call(elem, e) - } - } - } - } - - /********************************************************************* - * é…置系统 * - **********************************************************************/ - - function kernel(settings) { - for (var p in settings) { - if (!ohasOwn.call(settings, p)) - continue - var val = settings[p] - if (typeof kernel.plugins[p] === "function") { - kernel.plugins[p](val) - } else if (typeof kernel[p] === "object") { - avalon.mix(kernel[p], val) - } else { - kernel[p] = val - } - } - return this - } - - var openTag, closeTag, rexpr, rexprg, rbind, rregexp = /[-.*+?^${}()|[\]\/\\]/g - - function escapeRegExp(target) { - //http://stevenlevithan.com/regex/xregexp/ - //将字符串安全格å¼åŒ–为正则表达å¼çš„æºç  - return (target + "").replace(rregexp, "\\$&") - } - - var plugins = { - loader: function (builtin) { - var flag = innerRequire && builtin - window.require = flag ? innerRequire : otherRequire - window.define = flag ? innerRequire.define : otherDefine - }, - interpolate: function (array) { - openTag = array[0] - closeTag = array[1] - if (openTag === closeTag) { - throw new SyntaxError("openTag!==closeTag") - } else if (array + "" === "") { - kernel.commentInterpolate = true - } else { - var test = openTag + "test" + closeTag - cinerator.innerHTML = test - if (cinerator.innerHTML !== test && cinerator.innerHTML.indexOf("<") > -1) { - throw new SyntaxError("此定界符ä¸åˆæ³•") - } - cinerator.innerHTML = "" - } - var o = escapeRegExp(openTag), - c = escapeRegExp(closeTag) - rexpr = new RegExp(o + "(.*?)" + c) - rexprg = new RegExp(o + "(.*?)" + c, "g") - rbind = new RegExp(o + ".*?" + c + "|\\sms-") - } - } - - kernel.debug = true - kernel.plugins = plugins - kernel.plugins['interpolate'](["{{", "}}"]) - kernel.paths = {} - kernel.shim = {} - kernel.maxRepeatSize = 100 - avalon.config = kernel - var ravalon = /(\w+)\[(avalonctrl)="(\S+)"\]/ - var findNodes = function (str) { - return DOC.querySelectorAll(str) - } - /********************************************************************* - * 事件总线 * - **********************************************************************/ - var EventBus = { - $watch: function (type, callback) { - if (typeof callback === "function") { - var callbacks = this.$events[type] - if (callbacks) { - callbacks.push(callback) - } else { - this.$events[type] = [callback] - } - } else { //é‡æ–°å¼€å§‹ç›‘å¬æ­¤VM的第一é‡ç®€å•å±žæ€§çš„å˜åŠ¨ - this.$events = this.$watch.backup - } - return this - }, - $unwatch: function (type, callback) { - var n = arguments.length - if (n === 0) { //让此VM的所有$watch回调无效化 - this.$watch.backup = this.$events - this.$events = {} - } else if (n === 1) { - this.$events[type] = [] - } else { - var callbacks = this.$events[type] || [] - var i = callbacks.length - while (~--i < 0) { - if (callbacks[i] === callback) { - return callbacks.splice(i, 1) - } - } - } - return this - }, - $fire: function (type) { - var special, i, v, callback - if (/^(\w+)!(\S+)$/.test(type)) { - special = RegExp.$1 - type = RegExp.$2 - } - var events = this.$events - if (!events) - return - var args = aslice.call(arguments, 1) - var detail = [type].concat(args) - if (special === "all") { - for (i in avalon.vmodels) { - v = avalon.vmodels[i] - if (v !== this) { - v.$fire.apply(v, detail) - } - } - } else if (special === "up" || special === "down") { - var elements = events.expr ? findNodes(events.expr) : [] - if (elements.length === 0) - return - for (i in avalon.vmodels) { - v = avalon.vmodels[i] - if (v !== this) { - if (v.$events.expr) { - var eventNodes = findNodes(v.$events.expr) - if (eventNodes.length === 0) { - continue - } - //循环两个vmodel中的节点,查找匹é…(å‘上匹é…或者å‘下匹é…)的节点并设置标识 - /* jshint ignore:start */ - Array.prototype.forEach.call(eventNodes, function (node) { - Array.prototype.forEach.call(elements, function (element) { - var ok = special === "down" ? element.contains(node) : //å‘下æ•èŽ· - node.contains(element) //å‘上冒泡 - if (ok) { - node._avalon = v //符åˆæ¡ä»¶çš„加一个标识 - } - }); - }) - /* jshint ignore:end */ - } - } - } - var nodes = DOC.getElementsByTagName("*") //å®žçŽ°èŠ‚ç‚¹æŽ’åº - var alls = [] - Array.prototype.forEach.call(nodes, function (el) { - if (el._avalon) { - alls.push(el._avalon) - el._avalon = "" - el.removeAttribute("_avalon") - } - }) - if (special === "up") { - alls.reverse() - } - for (i = 0; callback = alls[i++];) { - if (callback.$fire.apply(callback, detail) === false) { - break - } - } - } else { - var callbacks = events[type] || [] - var all = events.$all || [] - for (i = 0; callback = callbacks[i++];) { - if (isFunction(callback)) - callback.apply(this, args) - } - for (i = 0; callback = all[i++];) { - if (isFunction(callback)) - callback.apply(this, arguments) - } - } - } - } - - /********************************************************************* - * modelFactory * - **********************************************************************/ -//avalon最核心的方法的两个方法之一(å¦ä¸€ä¸ªæ˜¯avalon.scan),返回一个ViewModel(VM) - var VMODELS = avalon.vmodels = createMap() //所有vmodel都储存在这里 - avalon.define = function (id, factory) { - var $id = id.$id || id - if (!$id) { - log("warning: vm必须指定$id") - } - if (VMODELS[$id]) { - log("warning: " + $id + " å·²ç»å­˜åœ¨äºŽavalon.vmodels中") - } - if (typeof id === "object") { - var model = modelFactory(id) - } else { - var scope = { - $watch: noop - } - factory(scope) //得到所有定义 - model = modelFactory(scope) //å·å¤©æ¢æ—¥ï¼Œå°†scopeæ¢ä¸ºmodel - stopRepeatAssign = true - factory(model) - stopRepeatAssign = false - } - model.$id = $id - return VMODELS[$id] = model - } - -//一些ä¸éœ€è¦è¢«ç›‘å¬çš„属性 - var $$skipArray = String("$id,$watch,$unwatch,$fire,$events,$model,$skipArray").match(rword) - - function isObservable(name, value, $skipArray) { - if (isFunction(value) || value && value.nodeType) { - return false - } - if ($skipArray.indexOf(name) !== -1) { - return false - } - if ($$skipArray.indexOf(name) !== -1) { - return false - } - var $special = $skipArray.$special - if (name && name.charAt(0) === "$" && !$special[name]) { - return false - } - return true - } - -//ms-with,ms-each, ms-repeat绑定生æˆçš„代ç†å¯¹è±¡å‚¨å­˜æ±  - var midway = createMap() - - function getNewValue(accessor, name, value, $vmodel) { - switch (accessor.type) { - case 0://计算属性 - var getter = accessor.get - var setter = accessor.set - if (isFunction(setter)) { - var $events = $vmodel.$events - var lock = $events[name] - $events[name] = [] //清空回调,防止内部冒泡而触å‘多次$fire - setter.call($vmodel, value) - $events[name] = lock - } - return getter.call($vmodel) //åŒæ­¥$model - case 1://监控属性 - return value - case 2://对象属性(包括数组与哈希) - if (value !== $vmodel.$model[name]) { - var svmodel = accessor.svmodel = objectFactory($vmodel, name, value, accessor.valueType) - value = svmodel.$model //åŒæ­¥$model - var fn = midway[svmodel.$id] - fn && fn() //åŒæ­¥è§†å›¾ - } - return value - } - } - - function modelFactory(source, $special, $model) { - if (Array.isArray(source)) { - var arr = source.concat() - source.length = 0 - var collection = Collection(source)// jshint ignore:line - collection.pushArray(arr) - return collection - } - //0 null undefined || Node || VModel - if (!source || source.nodeType > 0 || (source.$id && source.$events)) { - return source - } - if (!Array.isArray(source.$skipArray)) { - source.$skipArray = [] - } - source.$skipArray.$special = $special || createMap() //强制è¦ç›‘å¬çš„属性 - var $vmodel = {} //è¦è¿”回的对象, 它在IE6-8下å¯èƒ½è¢«å·é¾™è½¬å‡¤ - $model = $model || {} //vmodels.$model属性 - var $events = createMap() //vmodel.$events属性 - var watchedProperties = createMap() //监控属性 - var initCallbacks = [] //åˆå§‹åŒ–æ‰æ‰§è¡Œçš„函数 - for (var i in source) { - (function (name, val) { - $model[name] = val - if (!isObservable(name, val, source.$skipArray)) { - return //过滤所有éžç›‘控属性 - } - //总共产生三ç§accessor - $events[name] = [] - var valueType = avalon.type(val) - var accessor = function (newValue) { - var name = accessor._name - var $vmodel = this - var $model = $vmodel.$model - var oldValue = $model[name] - var $events = $vmodel.$events - - if (arguments.length) { - if (stopRepeatAssign) { - return - } - //计算属性与对象属性需è¦é‡æ–°è®¡ç®—newValue - if (accessor.type !== 1) { - newValue = getNewValue(accessor, name, newValue, $vmodel) - if (!accessor.type) - return - } - if (!isEqual(oldValue, newValue)) { - $model[name] = newValue - notifySubscribers($events[name]) //åŒæ­¥è§†å›¾ - safeFire($vmodel, name, newValue, oldValue) //触å‘$watch回调 - } - } else { - if (accessor.type === 0) { //type 0 计算属性 1 监控属性 2 对象属性 - //计算属性ä¸éœ€è¦æ”¶é›†è§†å›¾åˆ·æ–°å‡½æ•°,都是由其他监控属性代劳 - newValue = accessor.get.call($vmodel) - if (oldValue !== newValue) { - $model[name] = newValue - //这里ä¸ç”¨åŒæ­¥è§†å›¾ - safeFire($vmodel, name, newValue, oldValue) //触å‘$watch回调 - } - return newValue - } else { - collectSubscribers($events[name]) //收集视图函数 - return accessor.svmodel || oldValue - } - } - } - //总共产生三ç§accessor - if (valueType === "object" && isFunction(val.get) && Object.keys(val).length <= 2) { - //第1ç§ä¸ºè®¡ç®—属性, å› å˜é‡ï¼Œé€šè¿‡å…¶ä»–监控属性触å‘å…¶æ”¹å˜ - accessor.set = val.set - accessor.get = val.get - accessor.type = 0 - initCallbacks.push(function () { - var data = { - evaluator: function () { - data.type = Math.random(), - data.element = null - $model[name] = accessor.get.call($vmodel) - }, - element: head, - type: Math.random(), - handler: noop, - args: [] - } - Registry[expose] = data - accessor.call($vmodel) - delete Registry[expose] - }) - } else if (rcomplexType.test(valueType)) { - //第2ç§ä¸ºå¯¹è±¡å±žæ€§ï¼Œäº§ç”Ÿå­VM与监控数组 - accessor.type = 2 - accessor.valueType = valueType - initCallbacks.push(function () { - var svmodel = modelFactory(val, 0, $model[name]) - accessor.svmodel = svmodel - svmodel.$events[subscribers] = $events[name] - }) - } else { - accessor.type = 1 - //第3ç§ä¸ºç›‘控属性,对应简å•çš„æ•°æ®ç±»åž‹ï¼Œè‡ªå˜é‡ - } - accessor._name = name - watchedProperties[name] = accessor - })(i, source[i])// jshint ignore:line - } - - $$skipArray.forEach(function (name) { - delete source[name] - delete $model[name] //这些特殊属性ä¸åº”该在$model中出现 - }) - - $vmodel = Object.defineProperties($vmodel, descriptorFactory(watchedProperties), source) //生æˆä¸€ä¸ªç©ºçš„ViewModel - for (var name in source) { - if (!watchedProperties[name]) { - $vmodel[name] = source[name] - } - } - //添加$id, $model, $events, $watch, $unwatch, $fire - $vmodel.$id = generateID() - $vmodel.$model = $model - $vmodel.$events = $events - for (i in EventBus) { - $vmodel[i] = EventBus[i] - } - - Object.defineProperty($vmodel, "hasOwnProperty", { - value: function (name) { - return name in this.$model - }, - writable: false, - enumerable: false, - configurable: true - }) - - initCallbacks.forEach(function (cb) { //收集ä¾èµ– - cb() - }) - return $vmodel - } - -//比较两个值是å¦ç›¸ç­‰ - var isEqual = Object.is || function (v1, v2) { - if (v1 === 0 && v2 === 0) { - return 1 / v1 === 1 / v2 - } else if (v1 !== v1) { - return v2 !== v2 - } else { - return v1 === v2 - } - } - - function safeFire(a, b, c, d) { - if (a.$events) { - EventBus.$fire.call(a, b, c, d) - } - } - - var descriptorFactory = function (obj) { - var descriptors = createMap() - for (var i in obj) { - descriptors[i] = { - get: obj[i], - set: obj[i], - enumerable: true, - configurable: true - } - } - return descriptors - } - -//应用于第2ç§accessor - function objectFactory(parent, name, value, valueType) { - //a为原æ¥çš„VM, b为新数组或新对象 - var son = parent[name] - if (valueType === "array") { - if (!Array.isArray(value) || son === value) { - return son //fix https://github.com/RubyLouvre/avalon/issues/261 - } - son._.$unwatch() - son.clear() - son._.$watch() - son.pushArray(value.concat()) - return son - } else { - var iterators = parent.$events[name] - var ret = modelFactory(value) - ret.$events[subscribers] = iterators - midway[ret.$id] = function (data) { - while (data = iterators.shift()) { - (function (el) { - avalon.nextTick(function () { - var type = el.type - if (type && bindingHandlers[type]) { //#753 - el.rollback && el.rollback() //还原 ms-with ms-on - bindingHandlers[type](el, el.vmodels) - } - }) - })(data)// jshint ignore:line - } - delete midway[ret.$id] - } - return ret - } - } - - /********************************************************************* - * 监控数组(与ms-each, ms-repeaté…åˆä½¿ç”¨ï¼‰ * - **********************************************************************/ - - function Collection(model) { - var array = [] - array.$id = generateID() - array.$model = model //æ•°æ®æ¨¡åž‹ - array.$events = {} - array.$events[subscribers] = [] - array._ = modelFactory({ - length: model.length - }) - array._.$watch("length", function (a, b) { - array.$fire("length", a, b) - }) - for (var i in EventBus) { - array[i] = EventBus[i] - } - array.$map = { - el: 1 - } - array.$proxy = [] - avalon.mix(array, CollectionPrototype) - return array - } - - function mutateArray(method, pos, n, index, method2, pos2, n2) { - var oldLen = this.length, loop = 2 - while (--loop) { - switch (method) { - case "add": - /* jshint ignore:start */ - var m = pos + n - var array = this.$model.slice(pos, m).map(function (el) { - if (rcomplexType.test(avalon.type(el))) {//转æ¢ä¸ºVM - return el.$id ? el : modelFactory(el, 0, el) - } else { - return el - } - }) - /* jshint ignore:end */ - for (var i = pos; i < m; i++) {//生æˆä»£ç†VM - var proxy = eachProxyAgent(i, this) - this.$proxy.splice(i, 0, proxy) - } - _splice.apply(this, [pos, 0].concat(array)) - this._fire("add", pos, n) - break - case "del": - var ret = this._splice(pos, n) - var removed = this.$proxy.splice(pos, n) //回收代ç†VM - recycleProxies(removed, "each") - this._fire("del", pos, n) - break - } - if (method2) { - method = method2 - pos = pos2 - n = n2 - loop = 2 - method2 = 0 - } - } - resetIndex(this.$proxy, index) - if (this.length !== oldLen) { - this._.length = this.length - } - return ret - } - - var _splice = ap.splice - var CollectionPrototype = { - _splice: _splice, - _fire: function (method, a, b) { - notifySubscribers(this.$events[subscribers], method, a, b) - }, - size: function () { //å–得数组长度,这个函数å¯ä»¥åŒæ­¥è§†å›¾ï¼Œlengthä¸èƒ½ - return this._.length - }, - pushArray: function (array) { - var m = array.length, n = this.length - if (m) { - ap.push.apply(this.$model, array) - mutateArray.call(this, "add", n, m, Math.max(0, n - 1)) - } - return m + n - }, - push: function () { - //http://jsperf.com/closure-with-arguments - var array = [] - var i, n = arguments.length - for (i = 0; i < n; i++) { - array[i] = arguments[i] - } - return this.pushArray(array) - }, - unshift: function () { - var m = arguments.length, n = this.length - if (m) { - ap.unshift.apply(this.$model, arguments) - mutateArray.call(this, "add", 0, m, 0) - } - return m + n //IE67çš„unshiftä¸ä¼šè¿”回长度 - }, - shift: function () { - if (this.length) { - var el = this.$model.shift() - mutateArray.call(this, "del", 0, 1, 0) - return el //返回被移除的元素 - } - }, - pop: function () { - var n = this.length - if (n) { - var el = this.$model.pop() - mutateArray.call(this, "del", n - 1, 1, Math.max(0, n - 2)) - return el //返回被移除的元素 - } - }, - splice: function (start) { - var m = arguments.length, args = [], change - var removed = _splice.apply(this.$model, arguments) - if (removed.length) { //如果用户删掉了元素 - args.push("del", start, removed.length, 0) - change = true - } - if (m > 2) { //如果用户添加了元素 - if (change) { - args.splice(3, 1, 0, "add", start, m - 2) - } else { - args.push("add", start, m - 2, 0) - } - change = true - } - if (change) { //返回被移除的元素 - return mutateArray.apply(this, args) - } else { - return [] - } - }, - contains: function (el) { //判定是å¦åŒ…å« - return this.indexOf(el) !== -1 - }, - remove: function (el) { //移除第一个等于给定值的元素 - return this.removeAt(this.indexOf(el)) - }, - removeAt: function (index) { //移除指定索引上的元素 - if (index >= 0) { - this.$model.splice(index, 1) - return mutateArray.call(this, "del", index, 1, 0) - } - return [] - }, - clear: function () { - recycleProxies(this.$proxy, "each") - this.$model.length = this.$proxy.length = this.length = this._.length = 0 //清空数组 - this._fire("clear", 0) - return this - }, - removeAll: function (all) { //移除N个元素 - if (Array.isArray(all)) { - all.forEach(function (el) { - this.remove(el) - }, this) - } else if (typeof all === "function") { - for (var i = this.length - 1; i >= 0; i--) { - var el = this[i] - if (all(el, i)) { - this.removeAt(i) - } - } - } else { - this.clear() - } - }, - ensure: function (el) { - if (!this.contains(el)) { //åªæœ‰ä¸å­˜åœ¨æ‰push - this.push(el) - } - return this - }, - set: function (index, val) { - if (index >= 0) { - var valueType = avalon.type(val) - if (val && val.$model) { - val = val.$model - } - var target = this[index] - if (valueType === "object") { - for (var i in val) { - if (target.hasOwnProperty(i)) { - target[i] = val[i] - } - } - } else if (valueType === "array") { - target.clear().push.apply(target, val) - } else if (target !== val) { - this[index] = val - this.$model[index] = val - var proxy = this.$proxy[index] - if (proxy) { - notifySubscribers(proxy.$events.el) - } - // this._fire("set", index, val) - } - } - return this - } - } -//相当于原æ¥bindingExecutors.repeat çš„index分支 - function resetIndex(array, pos) { - var last = array.length - 1 - for (var el; el = array[pos]; pos++) { - el.$index = pos - el.$first = pos === 0 - el.$last = pos === last - } - } - - function sortByIndex(array, indexes) { - var map = {}; - for (var i = 0, n = indexes.length; i < n; i++) { - map[i] = array[i] // preserve - var j = indexes[i] - if (j in map) { - array[i] = map[j] - delete map[j] - } else { - array[i] = array[j] - } - } - } - - "sort,reverse".replace(rword, function (method) { - CollectionPrototype[method] = function () { - var newArray = this.$model//这是è¦æŽ’åºçš„新数组 - var oldArray = newArray.concat() //ä¿æŒåŽŸæ¥çŠ¶æ€çš„旧数组 - var mask = Math.random() - var indexes = [] - var hasSort - ap[method].apply(newArray, arguments) //æŽ’åº - for (var i = 0, n = oldArray.length; i < n; i++) { - var neo = newArray[i] - var old = oldArray[i] - if (isEqual(neo, old)) { - indexes.push(i) - } else { - var index = oldArray.indexOf(neo) - indexes.push(index)//得到新数组的æ¯ä¸ªå…ƒç´ åœ¨æ—§æ•°ç»„对应的ä½ç½® - oldArray[index] = mask //å±è”½å·²ç»æ‰¾è¿‡çš„元素 - hasSort = true - } - } - if (hasSort) { - sortByIndex(this, indexes) - sortByIndex(this.$proxy, indexes) - this._fire("move", indexes) - resetIndex(this.$proxy, 0) - } - return this - } - }) - - /********************************************************************* - * ä¾èµ–调度系统 * - **********************************************************************/ - var ronduplex = /^(duplex|on)$/ - - avalon.injectBinding = function (data) { - Registry[expose] = data //暴光此函数,方便collectSubscribers收集 - avalon.openComputedCollect = true - var fn = data.evaluator - if (fn) { //如果是求值函数 - try { - var c = ronduplex.test(data.type) ? data : fn.apply(0, data.args) - if (!data.noRefresh) - data.handler(c, data.element, data) - } catch (e) { - //log("warning:exception throwed in [avalon.injectBinding] " + e) - delete data.evaluator - var node = data.element - if (node.nodeType === 3) { - var parent = node.parentNode - if (kernel.commentInterpolate) { - parent.replaceChild(DOC.createComment(data.value), node) - } else { - node.data = openTag + data.value + closeTag - } - } - } - } - avalon.openComputedCollect = false - delete Registry[expose] - } - - function collectSubscribers(list) { //收集ä¾èµ–于这个访问器的订阅者 - var data = Registry[expose] - if (list && data && avalon.Array.ensure(list, data) && data.element) { //åªæœ‰æ•°ç»„ä¸å­˜åœ¨æ­¤å…ƒç´ æ‰push进去 - addSubscribers(data, list) - } - } - - - function addSubscribers(data, list) { - data.$uuid = data.$uuid || generateID() - list.$uuid = list.$uuid || generateID() - var obj = { - data: data, - list: list, - $$uuid: data.$uuid + list.$uuid - } - if (!$$subscribers[obj.$$uuid]) { - $$subscribers[obj.$$uuid] = 1 - $$subscribers.push(obj) - } - } - - function disposeData(data) { - data.element = null - data.rollback && data.rollback() - for (var key in data) { - data[key] = null - } - } - - function isRemove(el) { - try {//IE下,如果文本节点脱离DOM树,访问parentNode会报错 - if (!el.parentNode) { - return true - } - } catch (e) { - return true - } - return el.msRetain ? 0 : (el.nodeType === 1 ? typeof el.sourceIndex === "number" ? - el.sourceIndex === 0 : !root.contains(el) : !avalon.contains(root, el)) - } - - var $$subscribers = avalon.$$subscribers = [] - var beginTime = new Date() - var oldInfo = {} - - function removeSubscribers() { - var i = $$subscribers.length - var n = i - var k = 0 - var obj - var types = [] - var newInfo = {} - var needTest = {} - while (obj = $$subscribers[--i]) { - var data = obj.data - var type = data.type - if (newInfo[type]) { - newInfo[type]++ - } else { - newInfo[type] = 1 - types.push(type) - } - } - var diff = false - types.forEach(function (type) { - if (oldInfo[type] !== newInfo[type]) { - needTest[type] = 1 - diff = true - } - }) - i = n - //avalon.log("需è¦æ£€æµ‹çš„个数 " + i) - if (diff) { - //avalon.log("有需è¦ç§»é™¤çš„元素") - while (obj = $$subscribers[--i]) { - data = obj.data - if (data.element === void 0) - continue - if (needTest[data.type] && isRemove(data.element)) { //如果它没有在DOMæ ‘ - k++ - $$subscribers.splice(i, 1) - delete $$subscribers[obj.$$uuid] - avalon.Array.remove(obj.list, data) - //log("debug: remove " + data.type) - disposeData(data) - obj.data = obj.list = null - } - } - } - oldInfo = newInfo - // avalon.log("å·²ç»ç§»é™¤çš„个数 " + k) - beginTime = new Date() - } - - function notifySubscribers(list) { //通知ä¾èµ–于这个访问器的订阅者更新自身 - if (list && list.length) { - if (new Date() - beginTime > 444 && typeof list[0] === "object") { - removeSubscribers() - } - var args = aslice.call(arguments, 1) - for (var i = list.length, fn; fn = list[--i];) { - var el = fn.element - if (el && el.parentNode) { - if (fn.$repeat) { - fn.handler.apply(fn, args) //处ç†ç›‘控数组的方法 - } else if (fn.type !== "on") { //事件绑定åªèƒ½ç”±ç”¨æˆ·è§¦å‘,ä¸èƒ½ç”±ç¨‹åºè§¦å‘ - var fun = fn.evaluator || noop - fn.handler(fun.apply(0, fn.args || []), el, fn) - } - } - } - } - } - - /************************************************************************ - * HTML处ç†(parseHTML, innerHTML, clearHTML) * - **************************************************************************/ -//parseHTML的辅助å˜é‡ - var tagHooks = new function () {// jshint ignore:line - avalon.mix(this, { - option: DOC.createElement("select"), - thead: DOC.createElement("table"), - td: DOC.createElement("tr"), - area: DOC.createElement("map"), - tr: DOC.createElement("tbody"), - col: DOC.createElement("colgroup"), - legend: DOC.createElement("fieldset"), - _default: DOC.createElement("div"), - "g": DOC.createElementNS("http://www.w3.org/2000/svg", "svg") - }) - this.optgroup = this.option - this.tbody = this.tfoot = this.colgroup = this.caption = this.thead - this.th = this.td - }// jshint ignore:line - - String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function (tag) { - tagHooks[tag] = tagHooks.g //处ç†SVG - }) - var rtagName = /<([\w:]+)/ - var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig - var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"]) - var script = DOC.createElement("script") - var rhtml = /<|&#?\w+;/ - avalon.parseHTML = function (html) { - var fragment = hyperspace.cloneNode(false) - if (typeof html !== "string") { - return fragment - } - if (!rhtml.test(html)) { - fragment.appendChild(DOC.createTextNode(html)) - return fragment - } - html = html.replace(rxhtml, "<$1>").trim() - var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(), - //å–得其标签å - wrapper = tagHooks[tag] || tagHooks._default, - firstChild - wrapper.innerHTML = html - var els = wrapper.getElementsByTagName("script") - if (els.length) { //使用innerHTML生æˆçš„script节点ä¸ä¼šå‘出请求与执行text属性 - for (var i = 0, el; el = els[i++];) { - if (scriptTypes[el.type]) { - var neo = script.cloneNode(false) //FFä¸èƒ½çœç•¥å‚æ•° - ap.forEach.call(el.attributes, function (attr) { - neo.setAttribute(attr.name, attr.value) - })// jshint ignore:line - neo.text = el.text - el.parentNode.replaceChild(neo, el) - } - } - } - - while (firstChild = wrapper.firstChild) { // å°†wrapperä¸Šçš„èŠ‚ç‚¹è½¬ç§»åˆ°æ–‡æ¡£ç¢Žç‰‡ä¸Šï¼ - fragment.appendChild(firstChild) - } - return fragment - } - - avalon.innerHTML = function (node, html) { - var a = this.parseHTML(html) - this.clearHTML(node).appendChild(a) - } - - avalon.clearHTML = function (node) { - node.textContent = "" - while (node.firstChild) { - node.removeChild(node.firstChild) - } - return node - } - - /********************************************************************* - * 扫æ系统 * - **********************************************************************/ - - avalon.scan = function (elem, vmodel) { - elem = elem || root - var vmodels = vmodel ? [].concat(vmodel) : [] - scanTag(elem, vmodels) - } - -//http://www.w3.org/TR/html5/syntax.html#void-elements - var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase()) - - function checkScan(elem, callback, innerHTML) { - var id = setTimeout(function () { - var currHTML = elem.innerHTML - clearTimeout(id) - if (currHTML === innerHTML) { - callback() - } else { - checkScan(elem, callback, currHTML) - } - }) - } - - - function createSignalTower(elem, vmodel) { - var id = elem.getAttribute("avalonctrl") || vmodel.$id - elem.setAttribute("avalonctrl", id) - vmodel.$events.expr = elem.tagName + '[avalonctrl="' + id + '"]' - } - - var getBindingCallback = function (elem, name, vmodels) { - var callback = elem.getAttribute(name) - if (callback) { - for (var i = 0, vm; vm = vmodels[i++];) { - if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") { - return vm[callback] - } - } - } - } - - function executeBindings(bindings, vmodels) { - for (var i = 0, data; data = bindings[i++];) { - data.vmodels = vmodels - bindingHandlers[data.type](data, vmodels) - if (data.evaluator && data.element && data.element.nodeType === 1) { //移除数æ®ç»‘å®šï¼Œé˜²æ­¢è¢«äºŒæ¬¡è§£æž - //chrome使用removeAttributeNode移除ä¸å­˜åœ¨çš„特性节点时会报错 https://github.com/RubyLouvre/avalon/issues/99 - data.element.removeAttribute(data.name) - } - } - bindings.length = 0 - } - -//https://github.com/RubyLouvre/avalon/issues/636 - var mergeTextNodes = IEVersion && window.MutationObserver ? function (elem) { - var node = elem.firstChild, text - while (node) { - var aaa = node.nextSibling - if (node.nodeType === 3) { - if (text) { - text.nodeValue += node.nodeValue - elem.removeChild(node) - } else { - text = node - } - } else { - text = null - } - node = aaa - } - } : 0 - - var rmsAttr = /ms-(\w+)-?(.*)/ - var priorityMap = { - "if": 10, - "repeat": 90, - "data": 100, - "widget": 110, - "each": 1400, - "with": 1500, - "duplex": 2000, - "on": 3000 - } - - var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit") - var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled") - - function bindingSorter(a, b) { - return a.priority - b.priority - } - - function scanAttr(elem, vmodels) { - //防止setAttribute, removeAttributeæ—¶ attributes自动被åŒæ­¥,导致for循环出错 - var attributes = elem.hasAttributes() ? avalon.slice(elem.attributes) : [] - var bindings = [], - msData = createMap(), - match - for (var i = 0, attr; attr = attributes[i++];) { - if (attr.specified) { - if (match = attr.name.match(rmsAttr)) { - //如果是以指定å‰ç¼€å‘½åçš„ - var type = match[1] - var param = match[2] || "" - var value = attr.value - var name = attr.name - msData[name] = value - if (events[type]) { - param = type - type = "on" - } else if (obsoleteAttrs[type]) { - log("warning!请改用ms-attr-" + type + "代替ms-" + type + "ï¼") - if (type === "enabled") {//åƒæŽ‰ms-enabled绑定,用ms-disabled代替 - log("warning!ms-enabled或ms-attr-enabledå·²ç»è¢«åºŸå¼ƒ") - type = "disabled" - value = "!(" + value + ")" - } - param = type - type = "attr" - elem.removeAttribute(name) - name = "ms-attr-" + param - elem.setAttribute(name, value) - match = [name] - msData[name] = value - } - if (typeof bindingHandlers[type] === "function") { - var binding = { - type: type, - param: param, - element: elem, - name: match[0], - value: value, - priority: type in priorityMap ? priorityMap[type] : type.charCodeAt(0) * 10 + (Number(param) || 0) - } - if (type === "html" || type === "text") { - var token = getToken(value) - avalon.mix(binding, token) - binding.filters = binding.filters.replace(rhasHtml, function () { - binding.type = "html" - binding.group = 1 - return "" - })// jshint ignore:line - } - if (name === "ms-if-loop") { - binding.priority += 100 - } - if (vmodels.length) { - bindings.push(binding) - if (type === "widget") { - elem.msData = elem.msData || msData - } - } - } - } - } - } - var control = elem.type - if (control && msData["ms-duplex"]) { - if (msData["ms-attr-checked"] && /radio|checkbox/.test(control)) { - log("warning!" + control + "控件ä¸èƒ½åŒæ—¶å®šä¹‰ms-attr-checked与ms-duplex") - } - if (msData["ms-attr-value"] && /text|password/.test(control)) { - log("warning!" + control + "控件ä¸èƒ½åŒæ—¶å®šä¹‰ms-attr-value与ms-duplex") - } - } - bindings.sort(bindingSorter) - var scanNode = true - for (i = 0; binding = bindings[i]; i++) { - type = binding.type - if (rnoscanAttrBinding.test(type)) { - return executeBindings(bindings.slice(0, i + 1), vmodels) - } else if (scanNode) { - scanNode = !rnoscanNodeBinding.test(type) - } - } - executeBindings(bindings, vmodels) - if (scanNode && !stopScan[elem.tagName] && rbind.test(elem.innerHTML + elem.textContent)) { - mergeTextNodes && mergeTextNodes(elem) - scanNodeList(elem, vmodels) //扫æå­å­™å…ƒç´  - } - } - - var rnoscanAttrBinding = /^if|widget|repeat$/ - var rnoscanNodeBinding = /^each|with|html|include$/ - - function scanNodeList(parent, vmodels) { - var node = parent.firstChild - while (node) { - var nextNode = node.nextSibling - scanNode(node, node.nodeType, vmodels) - node = nextNode - } - } - - function scanNodeArray(nodes, vmodels) { - for (var i = 0, node; node = nodes[i++];) { - scanNode(node, node.nodeType, vmodels) - } - } - - function scanNode(node, nodeType, vmodels) { - if (nodeType === 1) { - scanTag(node, vmodels) //扫æ元素节点 - if (node.msCallback) { - node.msCallback() - node.msCallback = void 0 - } - } else if (nodeType === 3 && rexpr.test(node.data)) { - scanText(node, vmodels) //扫æ文本节点 - } else if (kernel.commentInterpolate && nodeType === 8 && !rexpr.test(node.nodeValue)) { - scanText(node, vmodels) //扫æ注释节点 - } - } - - function scanTag(elem, vmodels, node) { - //扫æé¡ºåº ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100) - //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)åž«åŽ - var a = elem.getAttribute("ms-skip") - var b = elem.getAttributeNode("ms-important") - var c = elem.getAttributeNode("ms-controller") - if (typeof a === "string") { - return - } else if (node = b || c) { - var newVmodel = avalon.vmodels[node.value] - if (!newVmodel) { - return - } - //ms-importantä¸åŒ…å«çˆ¶VM,ms-controller相å - vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels) - elem.removeAttribute(node.name) //removeAttributeNodeä¸ä¼šåˆ·æ–°[ms-controller]æ ·å¼è§„则 - elem.classList.remove(node.name) - createSignalTower(elem, newVmodel) - } - scanAttr(elem, vmodels) //扫æ特性节点 - } - - var rhasHtml = /\|\s*html\s*/, - r11a = /\|\|/g, - rlt = /</g, - rgt = />/g, - rstringLiteral = /(['"])(\\\1|.)+?\1/g - - function getToken(value) { - if (value.indexOf("|") > 0) { - var scapegoat = value.replace(rstringLiteral, function (_) { - return Array(_.length + 1).join("1")// jshint ignore:line - }) - var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或 - if (index > -1) { - return { - filters: value.slice(index), - value: value.slice(0, index), - expr: true - } - } - } - return { - value: value, - filters: "", - expr: true - } - } - - function scanExpr(str) { - var tokens = [], - value, start = 0, - stop - do { - stop = str.indexOf(openTag, start) - if (stop === -1) { - break - } - value = str.slice(start, stop) - if (value) { // {{ 左边的文本 - tokens.push({ - value: value, - filters: "", - expr: false - }) - } - start = stop + openTag.length - stop = str.indexOf(closeTag, start) - if (stop === -1) { - break - } - value = str.slice(start, stop) - if (value) { //处ç†{{ }}æ’å€¼è¡¨è¾¾å¼ - tokens.push(getToken(value)) - } - start = stop + closeTag.length - } while (1) - value = str.slice(start) - if (value) { //}} å³è¾¹çš„文本 - tokens.push({ - value: value, - expr: false, - filters: "" - }) - } - return tokens - } - - function scanText(textNode, vmodels) { - var bindings = [] - if (textNode.nodeType === 8) { - var token = getToken(textNode.nodeValue) - var tokens = [token] - } else { - tokens = scanExpr(textNode.data) - } - if (tokens.length) { - for (var i = 0; token = tokens[i++];) { - var node = DOC.createTextNode(token.value) //将文本转æ¢ä¸ºæ–‡æœ¬èŠ‚点,并替æ¢åŽŸæ¥çš„文本节点 - if (token.expr) { - token.type = "text" - token.element = node - token.filters = token.filters.replace(rhasHtml, function () { - token.type = "html" - token.group = 1 - return "" - })// jshint ignore:line - bindings.push(token) //收集带有æ’值表达å¼çš„文本 - } - hyperspace.appendChild(node) - } - textNode.parentNode.replaceChild(hyperspace, textNode) - if (bindings.length) - executeBindings(bindings, vmodels) - } - } - - /********************************************************************* - * avalon的原型方法定义区 * - **********************************************************************/ - - function hyphen(target) { - //转æ¢ä¸ºè¿žå­—符线风格 - return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase() - } - - function camelize(target) { - //转æ¢ä¸ºé©¼å³°é£Žæ ¼ - if (target.indexOf("-") < 0 && target.indexOf("_") < 0) { - return target //æå‰åˆ¤æ–­ï¼Œæ高getStyle等的效率 - } - return target.replace(/[-_][^-_]/g, function (match) { - return match.charAt(1).toUpperCase() - }) - } - - "add,remove".replace(rword, function (method) { - avalon.fn[method + "Class"] = function (cls) { - var el = this[0] - //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26 - if (cls && typeof cls === "string" && el && el.nodeType === 1) { - cls.replace(/\S+/g, function (c) { - el.classList[method](c) - }) - } - return this - } - }) - - avalon.fn.mix({ - hasClass: function (cls) { - var el = this[0] || {} //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支æŒclassList,chrome24+,firefox26+支æŒclassList2.0 - return el.nodeType === 1 && el.classList.contains(cls) - }, - toggleClass: function (value, stateVal) { - var className, i = 0 - var classNames = String(value).split(/\s+/) - var isBool = typeof stateVal === "boolean" - while ((className = classNames[i++])) { - var state = isBool ? stateVal : !this.hasClass(className) - this[state ? "addClass" : "removeClass"](className) - } - return this - }, - attr: function (name, value) { - if (arguments.length === 2) { - this[0].setAttribute(name, value) - return this - } else { - return this[0].getAttribute(name) - } - }, - data: function (name, value) { - name = "data-" + hyphen(name || "") - switch (arguments.length) { - case 2: - this.attr(name, value) - return this - case 1: - var val = this.attr(name) - return parseData(val) - case 0: - var ret = {} - ap.forEach.call(this[0].attributes, function (attr) { - if (attr) { - name = attr.name - if (!name.indexOf("data-")) { - name = camelize(name.slice(5)) - ret[name] = parseData(attr.value) - } - } - }) - return ret - } - }, - removeData: function (name) { - name = "data-" + hyphen(name) - this[0].removeAttribute(name) - return this - }, - css: function (name, value) { - if (avalon.isPlainObject(name)) { - for (var i in name) { - avalon.css(this, i, name[i]) - } - } else { - var ret = avalon.css(this, name, value) - } - return ret !== void 0 ? ret : this - }, - position: function () { - var offsetParent, offset, - elem = this[0], - parentOffset = { - top: 0, - left: 0 - }; - if (!elem) { - return - } - if (this.css("position") === "fixed") { - offset = elem.getBoundingClientRect() - } else { - offsetParent = this.offsetParent() //得到真正的offsetParent - offset = this.offset() // 得到正确的offsetParent - if (offsetParent[0].tagName !== "HTML") { - parentOffset = offsetParent.offset() - } - parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true) - parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true) - // Subtract offsetParent scroll positions - parentOffset.top -= offsetParent.scrollTop() - parentOffset.left -= offsetParent.scrollLeft() - } - return { - top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true), - left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true) - } - }, - offsetParent: function () { - var offsetParent = this[0].offsetParent - while (offsetParent && avalon.css(offsetParent, "position") === "static") { - offsetParent = offsetParent.offsetParent; - } - return avalon(offsetParent || root) - }, - bind: function (type, fn, phase) { - if (this[0]) { //此方法ä¸ä¼šé“¾ - return avalon.bind(this[0], type, fn, phase) - } - }, - unbind: function (type, fn, phase) { - if (this[0]) { - avalon.unbind(this[0], type, fn, phase) - } - return this - }, - val: function (value) { - var node = this[0] - if (node && node.nodeType === 1) { - var get = arguments.length === 0 - var access = get ? ":get" : ":set" - var fn = valHooks[getValType(node) + access] - if (fn) { - var val = fn(node, value) - } else if (get) { - return (node.value || "").replace(/\r/g, "") - } else { - node.value = value - } - } - return get ? val : this - } - }) - - if (root.dataset) { - avalon.fn.data = function (name, val) { - name = name && camelize(name) - var dataset = this[0].dataset - switch (arguments.length) { - case 2: - dataset[name] = val - return this - case 1: - val = dataset[name] - return parseData(val) - case 0: - var ret = createMap() - for (name in dataset) { - ret[name] = parseData(dataset[name]) - } - return ret - } - } - } - var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/ - avalon.parseJSON = JSON.parse - - function parseData(data) { - try { - if (typeof data === "object") - return data - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? JSON.parse(data) : data - } catch (e) { - } - return data - } - - avalon.each({ - scrollLeft: "pageXOffset", - scrollTop: "pageYOffset" - }, function (method, prop) { - avalon.fn[method] = function (val) { - var node = this[0] || {}, win = getWindow(node), - top = method === "scrollTop" - if (!arguments.length) { - return win ? win[prop] : node[method] - } else { - if (win) { - win.scrollTo(!top ? val : win[prop], top ? val : win[prop]) - } else { - node[method] = val - } - } - } - }) - - function getWindow(node) { - return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView : false - } - -//=============================css相关================================== - var cssHooks = avalon.cssHooks = createMap() - var prefixes = ["", "-webkit-", "-moz-", "-ms-"] //去掉opera-15çš„æ”¯æŒ - var cssMap = { - "float": "cssFloat" - } - avalon.cssNumber = oneObject("columnCount,order,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom") - - avalon.cssName = function (name, host, camelCase) { - if (cssMap[name]) { - return cssMap[name] - } - host = host || root.style - for (var i = 0, n = prefixes.length; i < n; i++) { - camelCase = camelize(prefixes[i] + name) - if (camelCase in host) { - return (cssMap[name] = camelCase) - } - } - return null - } - cssHooks["@:set"] = function (node, name, value) { - node.style[name] = value - } - - cssHooks["@:get"] = function (node, name) { - if (!node || !node.style) { - throw new Error("getComputedStyleè¦æ±‚传入一个节点 " + node) - } - var ret, computed = getComputedStyle(node) - if (computed) { - ret = name === "filter" ? computed.getPropertyValue(name) : computed[name] - if (ret === "") { - ret = node.style[name] //其他æµè§ˆå™¨éœ€è¦æˆ‘们手动å–内è”æ ·å¼ - } - } - return ret - } - cssHooks["opacity:get"] = function (node) { - var ret = cssHooks["@:get"](node, "opacity") - return ret === "" ? "1" : ret - } - - "top,left".replace(rword, function (name) { - cssHooks[name + ":get"] = function (node) { - var computed = cssHooks["@:get"](node, name) - return /px$/.test(computed) ? computed : - avalon(node).position()[name] + "px" - } - }) - var cssShow = { - position: "absolute", - visibility: "hidden", - display: "block" - } - var rdisplayswap = /^(none|table(?!-c[ea]).+)/ - - function showHidden(node, array) { - //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html - if (node.offsetWidth <= 0) { //opera.offsetWidthå¯èƒ½å°äºŽ0 - var styles = getComputedStyle(node, null) - if (rdisplayswap.test(styles["display"])) { - var obj = { - node: node - } - for (var name in cssShow) { - obj[name] = styles[name] - node.style[name] = cssShow[name] - } - array.push(obj) - } - var parent = node.parentNode - if (parent && parent.nodeType === 1) { - showHidden(parent, array) - } - } - } - - "Width,Height".replace(rword, function (name) { //fix 481 - var method = name.toLowerCase(), - clientProp = "client" + name, - scrollProp = "scroll" + name, - offsetProp = "offset" + name - cssHooks[method + ":get"] = function (node, which, override) { - var boxSizing = -4 - if (typeof override === "number") { - boxSizing = override - } - which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"] - var ret = node[offsetProp] // border-box 0 - if (boxSizing === 2) { // margin-box 2 - return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true) - } - if (boxSizing < 0) { // padding-box -2 - ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true) - } - if (boxSizing === -4) { // content-box -4 - ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true) - } - return ret - } - cssHooks[method + "&get"] = function (node) { - var hidden = []; - showHidden(node, hidden); - var val = cssHooks[method + ":get"](node) - for (var i = 0, obj; obj = hidden[i++];) { - node = obj.node - for (var n in obj) { - if (typeof obj[n] === "string") { - node.style[n] = obj[n] - } - } - } - return val; - } - avalon.fn[method] = function (value) { //会忽视其display - var node = this[0] - if (arguments.length === 0) { - if (node.setTimeout) { //å–得窗å£å°ºå¯¸,IE9åŽå¯ä»¥ç”¨node.innerWidth /innerHeight代替 - return node["inner" + name] - } - if (node.nodeType === 9) { //å–得页é¢å°ºå¯¸ - var doc = node.documentElement - //FF chrome html.scrollHeight< body.scrollHeight - //IE æ ‡å‡†æ¨¡å¼ : html.scrollHeight> body.scrollHeight - //IE æ€ªå¼‚æ¨¡å¼ : html.scrollHeight 最大等于å¯è§†çª—å£å¤šä¸€ç‚¹ï¼Ÿ - return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp]) - } - return cssHooks[method + "&get"](node) - } else { - return this.css(method, value) - } - } - avalon.fn["inner" + name] = function () { - return cssHooks[method + ":get"](this[0], void 0, -2) - } - avalon.fn["outer" + name] = function (includeMargin) { - return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0) - } - }) - avalon.fn.offset = function () { //å–å¾—è·ç¦»é¡µé¢å·¦å³è§’çš„åæ ‡ - var node = this[0] - try { - var rect = node.getBoundingClientRect() - // Make sure element is not hidden (display: none) or disconnected - // https://github.com/jquery/jquery/pull/2043/files#r23981494 - if (rect.width || rect.height || node.getClientRects().length) { - var doc = node.ownerDocument - var root = doc.documentElement - var win = doc.defaultView - return { - top: rect.top + win.pageYOffset - root.clientTop, - left: rect.left + win.pageXOffset - root.clientLeft - } - } - } catch (e) { - return { - left: 0, - top: 0 - } - } - } - //=============================val相关======================= - - function getValType(elem) { - var ret = elem.tagName.toLowerCase() - return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret - } - - var valHooks = { - "select:get": function (node, value) { - var option, options = node.options, - index = node.selectedIndex, - one = node.type === "select-one" || index < 0, - values = one ? null : [], - max = one ? index + 1 : options.length, - i = index < 0 ? max : one ? index : 0 - for (; i < max; i++) { - option = options[i] - //æ—§å¼IE在resetåŽä¸ä¼šæ”¹å˜selected,需è¦æ”¹ç”¨i === index判定 - //我们过滤所有disabledçš„option元素,但在safari5下,如果设置select为disable,那么其所有孩å­éƒ½disable - //因此当一个元素为disable,需è¦æ£€æµ‹å…¶æ˜¯å¦æ˜¾å¼è®¾ç½®äº†disableåŠå…¶çˆ¶èŠ‚点的disable情况 - if ((option.selected || i === index) && !option.disabled) { - value = option.value - if (one) { - return value - } - //收集所有selected值组æˆæ•°ç»„返回 - values.push(value) - } - } - return values - }, - "select:set": function (node, values, optionSet) { - values = [].concat(values) //强制转æ¢ä¸ºæ•°ç»„ - for (var i = 0, el; el = node.options[i++];) { - if ((el.selected = values.indexOf(el.value) > -1)) { - optionSet = true - } - } - if (!optionSet) { - node.selectedIndex = -1 - } - } - } - /********************************************************************* - * 编译系统 * - **********************************************************************/ - var quote = JSON.stringify - - var keywords = [ - "break,case,catch,continue,debugger,default,delete,do,else,false", - "finally,for,function,if,in,instanceof,new,null,return,switch,this", - "throw,true,try,typeof,var,void,while,with", /* 关键字*/ - "abstract,boolean,byte,char,class,const,double,enum,export,extends", - "final,float,goto,implements,import,int,interface,long,native", - "package,private,protected,public,short,static,super,synchronized", - "throws,transient,volatile", /*ä¿ç•™å­—*/ - "arguments,let,yield,undefined" /* ECMA 5 - use strict*/].join(",") - var rrexpstr = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g - var rsplit = /[^\w$]+/g - var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g') - var rnumber = /\b\d[^,]*/g - var rcomma = /^,+|,+$/g - var cacheVars = new Cache(512) - var getVariables = function (code) { - var key = "," + code.trim() - var ret = cacheVars.get(key) - if (ret) { - return ret - } - var match = code - .replace(rrexpstr, "") - .replace(rsplit, ",") - .replace(rkeywords, "") - .replace(rnumber, "") - .replace(rcomma, "") - .split(/^$|,+/) - return cacheVars.put(key, uniqSet(match)) - } - /*添加赋值语å¥*/ - - function addAssign(vars, scope, name, data) { - var ret = [], - prefix = " = " + name + "." - var isProxy = /\$proxy\$each/.test(scope.$id) - for (var i = vars.length, prop; prop = vars[--i];) { - var el = isProxy && scope.$map[prop] ? "el" : prop - if (scope.hasOwnProperty(el)) { - ret.push(prop + prefix + el) - data.vars.push(prop) - if (data.type === "duplex") { - vars.get = name + "." + el - } - vars.splice(i, 1) - } - } - return ret - } - - function uniqSet(array) { - var ret = [], - unique = {} - for (var i = 0; i < array.length; i++) { - var el = array[i] - var id = el && typeof el.$id === "string" ? el.$id : el - if (!unique[id]) { - unique[id] = ret.push(el) - } - } - return ret - } - -//缓存求值函数,以便多次利用 - var cacheExprs = new Cache(128) -//å–得求值函数åŠå…¶ä¼ å‚ - var rduplex = /\w\[.*\]|\w\.\w/ - var rproxy = /(\$proxy\$[a-z]+)\d+$/ - var rthimRightParentheses = /\)\s*$/ - var rthimOtherParentheses = /\)\s*\|/g - var rquoteFilterName = /\|\s*([$\w]+)/g - var rpatchBracket = /"\s*\["/g - var rthimLeftParentheses = /"\s*\(/g - - function parseFilter(val, filters) { - filters = filters - .replace(rthimRightParentheses, "")//处ç†æœ€åŽçš„å°æ‹¬å· - .replace(rthimOtherParentheses, function () {//处ç†å…¶ä»–å°æ‹¬å· - return "],|" - }) - .replace(rquoteFilterName, function (a, b) { //处ç†|åŠå®ƒåŽé¢çš„过滤器的åå­— - return "[" + quote(b) - }) - .replace(rpatchBracket, function () { - return '"],["' - }) - .replace(rthimLeftParentheses, function () { - return '",' - }) + "]" - return "return avalon.filters.$filter(" + val + ", " + filters + ")" - } - - function parseExpr(code, scopes, data) { - var dataType = data.type - var filters = data.filters || "" - var exprId = scopes.map(function (el) { - return String(el.$id).replace(rproxy, "$1") - }) + code + dataType + filters - var vars = getVariables(code).concat(), - assigns = [], - names = [], - args = [], - prefix = "" - //args 是一个对象数组, names 是将è¦ç”Ÿæˆçš„求值函数的å‚æ•° - scopes = uniqSet(scopes) - data.vars = [] - for (var i = 0, sn = scopes.length; i < sn; i++) { - if (vars.length) { - var name = "vm" + expose + "_" + i - names.push(name) - args.push(scopes[i]) - assigns.push.apply(assigns, addAssign(vars, scopes[i], name, data)) - } - } - if (!assigns.length && dataType === "duplex") { - return - } - if (dataType !== "duplex" && (code.indexOf("||") > -1 || code.indexOf("&&") > -1)) { - //https://github.com/RubyLouvre/avalon/issues/583 - data.vars.forEach(function (v) { - var reg = new RegExp("\\b" + v + "(?:\\.\\w+|\\[\\w+\\])+", "ig") - code = code.replace(reg, function (_) { - var c = _.charAt(v.length) - var r = IEVersion ? code.slice(arguments[1] + _.length) : RegExp.rightContext - var method = /^\s*\(/.test(r) - if (c === "." || c === "[" || method) {//比如v为aa,我们åªåŒ¹é…aa.bb,aa[cc],ä¸åŒ¹é…aaa.xxx - var name = "var" + String(Math.random()).replace(/^0\./, "") - if (method) {//array.size() - var array = _.split(".") - if (array.length > 2) { - var last = array.pop() - assigns.push(name + " = " + array.join(".")) - return name + "." + last - } else { - return _ - } - } - assigns.push(name + " = " + _) - return name - } else { - return _ - } - }) - }) - } - //---------------args---------------- - data.args = args - //---------------cache---------------- - var fn = cacheExprs.get(exprId) //直接从缓存,å…å¾—é‡å¤ç”Ÿæˆ - if (fn) { - data.evaluator = fn - return - } - prefix = assigns.join(", ") - if (prefix) { - prefix = "var " + prefix - } - if (/\S/.test(filters)) { //文本绑定,åŒå·¥ç»‘定æ‰æœ‰è¿‡æ»¤å™¨ - if (!/text|html/.test(data.type)) { - throw Error("ms-" + data.type + "ä¸æ”¯æŒè¿‡æ»¤å™¨") - } - code = "\nvar ret" + expose + " = " + code + ";\r\n" - code += parseFilter("ret" + expose, filters) - } else if (dataType === "duplex") { //åŒå·¥ç»‘定 - var _body = "'use strict';\nreturn function(vvv){\n\t" + - prefix + - ";\n\tif(!arguments.length){\n\t\treturn " + - code + - "\n\t}\n\t" + (!rduplex.test(code) ? vars.get : code) + - "= vvv;\n} " - try { - fn = Function.apply(noop, names.concat(_body)) - data.evaluator = cacheExprs.put(exprId, fn) - } catch (e) { - log("debug: parse error," + e.message) - } - return - } else if (dataType === "on") { //事件绑定 - if (code.indexOf("(") === -1) { - code += ".call(this, $event)" - } else { - code = code.replace("(", ".call(this,") - } - names.push("$event") - code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需è¦Function("return ;") - var lastIndex = code.lastIndexOf("\nreturn") - var header = code.slice(0, lastIndex) - var footer = code.slice(lastIndex) - code = header + "\n" + footer - } else { //其他绑定 - code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需è¦Function("return ;") - } - try { - fn = Function.apply(noop, names.concat("'use strict';\n" + prefix + code)) - data.evaluator = cacheExprs.put(exprId, fn) - } catch (e) { - log("debug: parse error," + e.message) - } finally { - vars = assigns = names = null //释放内存 - } - } - - -//parseExprçš„æ™ºèƒ½å¼•ç”¨ä»£ç† - - function parseExprProxy(code, scopes, data, tokens, noRegister) { - if (Array.isArray(tokens)) { - code = tokens.map(function (el) { - return el.expr ? "(" + el.value + ")" : quote(el.value) - }).join(" + ") - } - parseExpr(code, scopes, data) - if (data.evaluator && !noRegister) { - data.handler = bindingExecutors[data.handlerName || data.type] - //方便调试 - //这里éžå¸¸é‡è¦,我们通过判定视图刷新函数的element是å¦åœ¨DOM树决定 - //将它移出订阅者列表 - avalon.injectBinding(data) - } - } - - avalon.parseExprProxy = parseExprProxy - var bools = ["autofocus,autoplay,async,allowTransparency,checked,controls", - "declare,disabled,defer,defaultChecked,defaultSelected", - "contentEditable,isMap,loop,multiple,noHref,noResize,noShade", - "open,readOnly,selected" - ].join(",") - var boolMap = {} - bools.replace(rword, function (name) { - boolMap[name.toLowerCase()] = name - }) - - var propMap = { //属性å映射 - "accept-charset": "acceptCharset", - "char": "ch", - "charoff": "chOff", - "class": "className", - "for": "htmlFor", - "http-equiv": "httpEquiv" - } - - var anomaly = ["accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan", - "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight", - "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign" - ].join(",") - anomaly.replace(rword, function (name) { - propMap[name.toLowerCase()] = name - }) - - var rnoscripts = /(?:[\s\S]+?)<\/noscript>/img - var rnoscriptText = /([\s\S]+?)<\/noscript>/im - - var getXHR = function () { - return new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP") // jshint ignore:line - } - - var cacheTmpls = avalon.templateCache = {} - - bindingHandlers.attr = function (data, vmodels) { - var text = data.value.trim(), - simple = true - if (text.indexOf(openTag) > -1 && text.indexOf(closeTag) > 2) { - simple = false - if (rexpr.test(text) && RegExp.rightContext === "" && RegExp.leftContext === "") { - simple = true - text = RegExp.$1 - } - } - if (data.type === "include") { - var elem = data.element - data.includeRendered = getBindingCallback(elem, "data-include-rendered", vmodels) - data.includeLoaded = getBindingCallback(elem, "data-include-loaded", vmodels) - var outer = data.includeReplace = !!avalon(elem).data("includeReplace") - if (avalon(elem).data("includeCache")) { - data.templateCache = {} - } - data.startInclude = DOC.createComment("ms-include") - data.endInclude = DOC.createComment("ms-include-end") - if (outer) { - data.element = data.startInclude - elem.parentNode.insertBefore(data.startInclude, elem) - elem.parentNode.insertBefore(data.endInclude, elem.nextSibling) - } else { - elem.insertBefore(data.startInclude, elem.firstChild) - elem.appendChild(data.endInclude) - } - } - data.handlerName = "attr" //handleName用于处ç†å¤šç§ç»‘定共用åŒä¸€ç§bindingExecutor的情况 - parseExprProxy(text, vmodels, data, (simple ? 0 : scanExpr(data.value))) - } - - bindingExecutors.attr = function (val, elem, data) { - var method = data.type, - attrName = data.param - if (method === "css") { - avalon(elem).css(attrName, val) - } else if (method === "attr") { - // ms-attr-class="xxx" vm.xxx="aaa bbb ccc"将元素的className设置为aaa bbb ccc - // ms-attr-class="xxx" vm.xxx=false 清空元素的所有类å - // ms-attr-name="yyy" vm.yyy="ooo" 为元素设置name属性 - var toRemove = (val === false) || (val === null) || (val === void 0) - - if (!W3C && propMap[attrName]) { //æ—§å¼IE下需è¦è¿›è¡Œå字映射 - attrName = propMap[attrName] - } - var bool = boolMap[attrName] - if (typeof elem[bool] === "boolean") { - elem[bool] = !!val //布尔属性必须使用el.xxx = true|falseæ–¹å¼è®¾å€¼ - if (!val) { //如果为false, IE全系列下相当于setAttribute(xxx,''),会影å“到样å¼,需è¦è¿›ä¸€æ­¥å¤„ç† - toRemove = true - } - } - if (toRemove) { - return elem.removeAttribute(attrName) - } - - //SVGåªèƒ½ä½¿ç”¨setAttribute(xxx, yyy), VMLåªèƒ½ä½¿ç”¨elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy - var isInnate = rsvg.test(elem) ? false : (DOC.namespaces && isVML(elem)) ? true : attrName in elem.cloneNode(false) - if (isInnate) { - elem[attrName] = val - } else { - elem.setAttribute(attrName, val) - } - } else if (method === "include" && val) { - var vmodels = data.vmodels - var rendered = data.includeRendered - var loaded = data.includeLoaded - var replace = data.includeReplace - var target = replace ? elem.parentNode : elem - var scanTemplate = function (text) { - if (loaded) { - var newText = loaded.apply(target, [text].concat(vmodels)) - if (typeof newText === "string") - text = newText - } - if (rendered) { - checkScan(target, function () { - rendered.call(target) - }, NaN) - } - var lastID = data.includeLastID - if (data.templateCache && lastID && lastID !== val) { - var lastTemplate = data.templateCache[lastID] - if (!lastTemplate) { - lastTemplate = data.templateCache[lastID] = DOC.createElement("div") - ifGroup.appendChild(lastTemplate) - } - } - data.includeLastID = val - while (true) { - var node = data.startInclude.nextSibling - if (node && node !== data.endInclude) { - target.removeChild(node) - if (lastTemplate) - lastTemplate.appendChild(node) - } else { - break - } - } - var dom = getTemplateNodes(data, val, text) - var nodes = avalon.slice(dom.childNodes) - target.insertBefore(dom, data.endInclude) - scanNodeArray(nodes, vmodels) - } - - if (data.param === "src") { - if (typeof cacheTmpls[val] === "string") { - avalon.nextTick(function () { - scanTemplate(cacheTmpls[val]) - }) - } else if (Array.isArray(cacheTmpls[val])) { //#805 防止在循环绑定中å‘出许多相åŒçš„请求 - cacheTmpls[val].push(scanTemplate) - } else { - var xhr = getXHR() - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - var s = xhr.status - if (s >= 200 && s < 300 || s === 304 || s === 1223) { - var text = xhr.responseText - for (var f = 0, fn; fn = cacheTmpls[val][f++];) { - fn(text) - } - cacheTmpls[val] = text - } - } - } - cacheTmpls[val] = [scanTemplate] - xhr.open("GET", val, true) - if ("withCredentials" in xhr) { - xhr.withCredentials = true - } - xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") - xhr.send(null) - } - } else { - //IE系列与够新的标准æµè§ˆå™¨æ”¯æŒé€šè¿‡IDå–得元素(firefox14+) - //http://tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ - var el = val && val.nodeType === 1 ? val : DOC.getElementById(val) - if (el) { - if (el.tagName === "NOSCRIPT" && !(el.innerHTML || el.fixIE78)) { //IE7-8 innerText,innerHTML都无法å–得其内容,IE6能å–å¾—å…¶innerHTML - xhr = getXHR() //IE9-11与chromeçš„innerHTML会得到转义的内容,它们的innerTextå¯ä»¥ - xhr.open("GET", location, false) //谢谢Nodejs 乱炖群 深圳-纯属虚构 - xhr.send(null) - //http://bbs.csdn.net/topics/390349046?page=1#post-393492653 - var noscripts = DOC.getElementsByTagName("noscript") - var array = (xhr.responseText || "").match(rnoscripts) || [] - var n = array.length - for (var i = 0; i < n; i++) { - var tag = noscripts[i] - if (tag) { //IE6-8中noscript标签的innerHTML,innerText是åªè¯»çš„ - tag.style.display = "none" //http://haslayout.net/css/noscript-Ghost-Bug - tag.fixIE78 = (array[i].match(rnoscriptText) || ["", " "])[1] - } - } - } - avalon.nextTick(function () { - scanTemplate(el.fixIE78 || el.value || el.innerText || el.innerHTML) - }) - } - } - } else { - if (!root.hasAttribute && typeof val === "string" && (method === "src" || method === "href")) { - val = val.replace(/&/g, "&") //处ç†IE67自动转义的问题 - } - elem[method] = val - if (window.chrome && elem.tagName === "EMBED") { - var parent = elem.parentNode //#525 chrome1-37下embed标签动æ€è®¾ç½®srcä¸èƒ½å‘生请求 - var comment = document.createComment("ms-src") - parent.replaceChild(comment, elem) - parent.replaceChild(elem, comment) - } - } - } - - function getTemplateNodes(data, id, text) { - var div = data.templateCache && data.templateCache[id] - if (div) { - var dom = DOC.createDocumentFragment(), - firstChild - while (firstChild = div.firstChild) { - dom.appendChild(firstChild) - } - return dom - } - return avalon.parseHTML(text) - } - -//这几个指令都å¯ä»¥ä½¿ç”¨æ’值表达å¼ï¼Œå¦‚ms-src="aaa/{{b}}/{{c}}.html" - "title,alt,src,value,css,include,href".replace(rword, function (name) { - bindingHandlers[name] = bindingHandlers.attr - }) -//æ ¹æ®VM的属性值或表达å¼çš„值切æ¢ç±»å,ms-class="xxx yyy zzz:flag" -//http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html - bindingHandlers["class"] = function (data, vmodels) { - var oldStyle = data.param, - text = data.value, - rightExpr - data.handlerName = "class" - if (!oldStyle || isFinite(oldStyle)) { - data.param = "" //去掉数字 - var noExpr = text.replace(rexprg, function (a) { - return a.replace(/./g, "0") - //return Math.pow(10, a.length - 1) //å°†æ’值表达å¼æ’å…¥10çš„N-1次方æ¥å ä½ - }) - var colonIndex = noExpr.indexOf(":") //å–得第一个冒å·çš„ä½ç½® - if (colonIndex === -1) { // 比如 ms-class="aaa bbb ccc" 的情况 - var className = text - } else { // 比如 ms-class-1="ui-state-active:checked" 的情况 - className = text.slice(0, colonIndex) - rightExpr = text.slice(colonIndex + 1) - parseExpr(rightExpr, vmodels, data) //决定是添加还是删除 - if (!data.evaluator) { - log("debug: ms-class '" + (rightExpr || "").trim() + "' ä¸å­˜åœ¨äºŽVM中") - return false - } else { - data._evaluator = data.evaluator - data._args = data.args - } - } - var hasExpr = rexpr.test(className) //比如ms-class="width{{w}}"的情况 - if (!hasExpr) { - data.immobileClass = className - } - parseExprProxy("", vmodels, data, (hasExpr ? scanExpr(className) : 0)) - } else { - data.immobileClass = data.oldStyle = data.param - parseExprProxy(text, vmodels, data) - } - } - - bindingExecutors["class"] = function (val, elem, data) { - var $elem = avalon(elem), - method = data.type - if (method === "class" && data.oldStyle) { //如果是旧风格 - $elem.toggleClass(data.oldStyle, !!val) - } else { - //如果存在冒å·å°±æœ‰æ±‚值函数 - data.toggleClass = data._evaluator ? !!data._evaluator.apply(elem, data._args) : true - data.newClass = data.immobileClass || val - if (data.oldClass && data.newClass !== data.oldClass) { - $elem.removeClass(data.oldClass) - } - data.oldClass = data.newClass - switch (method) { - case "class": - $elem.toggleClass(data.newClass, data.toggleClass) - break - case "hover": - case "active": - if (!data.hasBindEvent) { //ç¡®ä¿åªç»‘定一次 - var activate = "mouseenter" //在移出移入时切æ¢ç±»å - var abandon = "mouseleave" - if (method === "active") { //在èšç„¦å¤±ç„¦ä¸­åˆ‡æ¢ç±»å - elem.tabIndex = elem.tabIndex || -1 - activate = "mousedown" - abandon = "mouseup" - var fn0 = $elem.bind("mouseleave", function () { - data.toggleClass && $elem.removeClass(data.newClass) - }) - } - var fn1 = $elem.bind(activate, function () { - data.toggleClass && $elem.addClass(data.newClass) - }) - var fn2 = $elem.bind(abandon, function () { - data.toggleClass && $elem.removeClass(data.newClass) - }) - data.rollback = function () { - $elem.unbind("mouseleave", fn0) - $elem.unbind(activate, fn1) - $elem.unbind(abandon, fn2) - } - data.hasBindEvent = true - } - break; - } - } - } - - "hover,active".replace(rword, function (method) { - bindingHandlers[method] = bindingHandlers["class"] - }) -//ms-controller绑定已ç»åœ¨scanTag 方法中实现 -//ms-css绑定已由ms-attr绑定实现 - - -// bindingHandlers.data 定义在if.js - bindingExecutors.data = function (val, elem, data) { - var key = "data-" + data.param - if (val && typeof val === "object") { - elem[key] = val - } else { - elem.setAttribute(key, String(val)) - } - } -//åŒå·¥ç»‘定 - var duplexBinding = bindingHandlers.duplex = function (data, vmodels) { - var elem = data.element, - hasCast - parseExprProxy(data.value, vmodels, data, 0, 1) - - data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop - if (data.evaluator && data.args) { - var params = [] - var casting = oneObject("string,number,boolean,checked") - if (elem.type === "radio" && data.param === "") { - data.param = "checked" - } - if (elem.msData) { - elem.msData["ms-duplex"] = data.value - } - data.param.replace(/\w+/g, function (name) { - if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) { - if (name === "radio") - log("ms-duplex-radioå·²ç»æ›´å为ms-duplex-checked") - name = "checked" - data.isChecked = true - } - if (name === "bool") { - name = "boolean" - log("ms-duplex-boolå·²ç»æ›´å为ms-duplex-boolean") - } else if (name === "text") { - name = "string" - log("ms-duplex-textå·²ç»æ›´å为ms-duplex-string") - } - if (casting[name]) { - hasCast = true - } - avalon.Array.ensure(params, name) - }) - if (!hasCast) { - params.push("string") - } - data.param = params.join("-") - data.bound = function (type, callback) { - if (elem.addEventListener) { - elem.addEventListener(type, callback, false) - } else { - elem.attachEvent("on" + type, callback) - } - var old = data.rollback - data.rollback = function () { - elem.avalonSetter = null - avalon.unbind(elem, type, callback) - old && old() - } - } - for (var i in avalon.vmodels) { - var v = avalon.vmodels[i] - v.$fire("avalon-ms-duplex-init", data) - } - var cpipe = data.pipe || (data.pipe = pipe) - cpipe(null, data, "init") - var tagName = elem.tagName - duplexBinding[tagName] && duplexBinding[tagName](elem, data.evaluator.apply(null, data.args), data) - } - } -//ä¸å­˜åœ¨ bindingExecutors.duplex - - function fixNull(val) { - return val == null ? "" : val - } - - avalon.duplexHooks = { - checked: { - get: function (val, data) { - return !data.element.oldValue - } - }, - string: { - get: function (val) { //åŒæ­¥åˆ°VM - return val - }, - set: fixNull - }, - "boolean": { - get: function (val) { - return val === "true" - }, - set: fixNull - }, - number: { - get: function (val, data) { - var number = parseFloat(val) - if (-val === -number) { - return number - } - var arr = /strong|medium|weak/.exec(data.element.getAttribute("data-duplex-number")) || ["medium"] - switch (arr[0]) { - case "strong": - return 0 - case "medium": - return val === "" ? "" : 0 - case "weak": - return val - } - }, - set: fixNull - } - } - - function pipe(val, data, action, e) { - data.param.replace(/\w+/g, function (name) { - var hook = avalon.duplexHooks[name] - if (hook && typeof hook[action] === "function") { - val = hook[action](val, data) - } - }) - return val - } - - var TimerID, ribbon = [] - - avalon.tick = function (fn) { - if (ribbon.push(fn) === 1) { - TimerID = setInterval(ticker, 60) - } - } - - function ticker() { - for (var n = ribbon.length - 1; n >= 0; n--) { - var el = ribbon[n] - if (el() === false) { - ribbon.splice(n, 1) - } - } - if (!ribbon.length) { - clearInterval(TimerID) - } - } - - var watchValueInTimer = noop - var rmsinput = /text|password|hidden/ - new function () { // jshint ignore:line - try { //#272 IE9-IE11, firefox - var setters = {} - var aproto = HTMLInputElement.prototype - var bproto = HTMLTextAreaElement.prototype - - function newSetter(value) { // jshint ignore:line - if (avalon.contains(root, this)) { - setters[this.tagName].call(this, value) - if (!rmsinput.test(this.type)) - return - if (!this.msFocus && this.avalonSetter) { - this.avalonSetter() - } - } - } - - var inputProto = HTMLInputElement.prototype - Object.getOwnPropertyNames(inputProto) //æ•…æ„引å‘IE6-8ç­‰æµè§ˆå™¨æŠ¥é”™ - setters["INPUT"] = Object.getOwnPropertyDescriptor(aproto, "value").set - Object.defineProperty(aproto, "value", { - set: newSetter - }) - setters["TEXTAREA"] = Object.getOwnPropertyDescriptor(bproto, "value").set - Object.defineProperty(bproto, "value", { - set: newSetter - }) - } catch (e) { - //在chrome 43中 ms-duplex终于ä¸éœ€è¦ä½¿ç”¨å®šæ—¶å™¨å®žçŽ°åŒå‘绑定了 - // http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype - // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1 - watchValueInTimer = avalon.tick - } - } // jshint ignore:line -//处ç†radio, checkbox, text, textarea, password - duplexBinding.INPUT = function (element, evaluator, data) { - var $type = element.type, - bound = data.bound, - $elem = avalon(element), - composing = false - - function callback(value) { - data.changed.call(this, value, data) - } - - function compositionStart() { - composing = true - } - - function compositionEnd() { - composing = false - } - - //当valueå˜åŒ–时改å˜model的值 - - var updateVModel = function () { - if (composing) //处ç†ä¸­æ–‡è¾“入法在minlengh下引å‘çš„BUG - return - var val = element.oldValue = element.value //防止递归调用形æˆæ­»å¾ªçŽ¯ - var lastValue = data.pipe(val, data, "get") - if ($elem.data("duplexObserve") !== false) { - evaluator(lastValue) - callback.call(element, lastValue) - if ($elem.data("duplex-focus")) { - avalon.nextTick(function () { - element.focus() - }) - } - } - } - //当modelå˜åŒ–æ—¶,它就会改å˜value的值 - data.handler = function () { - var val = data.pipe(evaluator(), data, "set") + "" - if (val !== element.oldValue) { - element.value = val - } - } - if (data.isChecked || $type === "radio") { - updateVModel = function () { - if ($elem.data("duplexObserve") !== false) { - var lastValue = data.pipe(element.value, data, "get") - evaluator(lastValue) - callback.call(element, lastValue) - } - } - data.handler = function () { - var val = evaluator() - var checked = data.isChecked ? !!val : val + "" === element.value - element.checked = element.oldValue = checked - } - bound("click", updateVModel) - } else if ($type === "checkbox") { - updateVModel = function () { - if ($elem.data("duplexObserve") !== false) { - var method = element.checked ? "ensure" : "remove" - var array = evaluator() - if (!Array.isArray(array)) { - log("ms-duplex应用于checkbox上è¦å¯¹åº”一个数组") - array = [array] - } - avalon.Array[method](array, data.pipe(element.value, data, "get")) - callback.call(element, array) - } - } - data.handler = function () { - var array = [].concat(evaluator()) //强制转æ¢ä¸ºæ•°ç»„ - element.checked = array.indexOf(data.pipe(element.value, data, "get")) > -1 - } - bound("change", updateVModel) - } else { - var events = element.getAttribute("data-duplex-event") || "input" - if (element.attributes["data-event"]) { - log("data-event指令已ç»åºŸå¼ƒï¼Œè¯·æ”¹ç”¨data-duplex-event") - } - events.replace(rword, function (name) { - switch (name) { - case "input": - bound("input", updateVModel) - bound("DOMAutoComplete", updateVModel) - if (!IEVersion) { - bound("compositionstart", compositionStart) - bound("compositionend", compositionEnd) - } - break - default: - bound(name, updateVModel) - break - } - }) - bound("focus", function () { - element.msFocus = true - }) - bound("blur", function () { - element.msFocus = false - }) - if (rmsinput.test($type)) { - watchValueInTimer(function () { - if (root.contains(element)) { - if (!element.msFocus && element.oldValue !== element.value) { - updateVModel() - } - } else if (!element.msRetain) { - return false - } - }) - } - - element.avalonSetter = updateVModel - } - - element.oldValue = element.value - avalon.injectBinding(data) - callback.call(element, element.value) - } - duplexBinding.TEXTAREA = duplexBinding.INPUT - duplexBinding.SELECT = function (element, evaluator, data) { - var $elem = avalon(element) - - function updateVModel() { - if ($elem.data("duplexObserve") !== false) { - var val = $elem.val() //字符串或字符串数组 - if (Array.isArray(val)) { - val = val.map(function (v) { - return data.pipe(v, data, "get") - }) - } else { - val = data.pipe(val, data, "get") - } - if (val + "" !== element.oldValue) { - evaluator(val) - } - data.changed.call(element, val, data) - } - } - - data.handler = function () { - var val = evaluator() - val = val && val.$model || val - if (Array.isArray(val)) { - if (!element.multiple) { - log("ms-duplex在ä¸èƒ½å¯¹åº”一个数组") - } - } - //å¿…é¡»å˜æˆå­—符串åŽæ‰èƒ½æ¯”较 - val = Array.isArray(val) ? val.map(String) : val + "" - if (val + "" !== element.oldValue) { - $elem.val(val) - element.oldValue = val + "" - } - } - data.bound("change", updateVModel) - element.msCallback = function () { - avalon.injectBinding(data) - data.changed.call(element, evaluator(), data) - } - } -// bindingHandlers.html 定义在if.js - bindingExecutors.html = function (val, elem, data) { - val = val == null ? "" : val - var isHtmlFilter = "group" in data - var parent = isHtmlFilter ? elem.parentNode : elem - if (!parent) - return - if (typeof val === "string") { - var fragment = avalon.parseHTML(val) - } else if (val.nodeType === 11) { //å°†val转æ¢ä¸ºæ–‡æ¡£ç¢Žç‰‡ - fragment = val - } else if (val.nodeType === 1 || val.item) { - var nodes = val.nodeType === 1 ? val.childNodes : val.item - fragment = hyperspace.cloneNode(true) - while (nodes[0]) { - fragment.appendChild(nodes[0]) - } - } - if (!fragment.firstChild) { - fragment.appendChild(DOC.createComment("ms-html")) - } - nodes = avalon.slice(fragment.childNodes) - //æ’å…¥å ä½ç¬¦, 如果是过滤器,需è¦æœ‰èŠ‚制地移除指定的数é‡,如果是html指令,直接清空 - if (isHtmlFilter) { - var n = data.group, - i = 1 - - data.group = nodes.length - data.element = nodes[0] - - while (i < n) { - var node = elem.nextSibling - if (node) { - parent.removeChild(node) - i++ - } - } - parent.replaceChild(fragment, elem) - } else { - avalon.clearHTML(parent).appendChild(fragment) - } - scanNodeArray(nodes, data.vmodels) - } - bindingHandlers["if"] = - bindingHandlers.data = - bindingHandlers.text = - bindingHandlers.html = - function (data, vmodels) { - parseExprProxy(data.value, vmodels, data) - } - - bindingExecutors["if"] = function (val, elem, data) { - if (val) { //æ’回DOMæ ‘ - if (elem.nodeType === 8) { - elem.parentNode.replaceChild(data.template, elem) - elem = data.element = data.template //这时å¯èƒ½ä¸ºnull - } - if (elem.getAttribute(data.name)) { - elem.removeAttribute(data.name) - scanAttr(elem, data.vmodels) - } - data.rollback = null - } else { //移出DOM树,并用注释节点å æ®åŽŸä½ç½® - if (elem.nodeType === 1) { - var node = data.element = DOC.createComment("ms-if") - elem.parentNode.replaceChild(node, elem) - data.template = elem //元素节点 - ifGroup.appendChild(elem) - data.rollback = function () { - if (elem.parentNode === ifGroup) { - ifGroup.removeChild(elem) - } - } - } - } - } -//ms-important绑定已ç»åœ¨scanTag 方法中实现 -//ms-include绑定已由ms-attr绑定实现 - - var rdash = /\(([^)]*)\)/ - bindingHandlers.on = function (data, vmodels) { - var value = data.value - data.type = "on" - var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10 - if (typeof bindingHandlers.on[eventType + "Hook"] === "function") { - bindingHandlers.on[eventType + "Hook"](data) - } - if (value.indexOf("(") > 0 && value.indexOf(")") > -1) { - var matched = (value.match(rdash) || ["", ""])[1].trim() - if (matched === "" || matched === "$event") { // aaa() aaa($event)当æˆaaaå¤„ç† - value = value.replace(rdash, "") - } - } - parseExprProxy(value, vmodels, data) - } - - bindingExecutors.on = function (callback, elem, data) { - callback = function (e) { - var fn = data.evaluator || noop - return fn.apply(this, data.args.concat(e)) - } - var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10 - if (eventType === "scan") { - callback.call(elem, { - type: eventType - }) - } else if (typeof data.specialBind === "function") { - data.specialBind(elem, callback) - } else { - var removeFn = avalon.bind(elem, eventType, callback) - } - data.rollback = function () { - if (typeof data.specialUnbind === "function") { - data.specialUnbind() - } else { - avalon.unbind(elem, eventType, removeFn) - } - } - } - bindingHandlers.repeat = function (data, vmodels) { - var type = data.type - parseExprProxy(data.value, vmodels, data, 0, 1) - var freturn = false - try { - var $repeat = data.$repeat = data.evaluator.apply(0, data.args || []) - var xtype = avalon.type($repeat) - if (xtype !== "object" && xtype !== "array") { - freturn = true - avalon.log("warning:" + data.value + "åªèƒ½æ˜¯å¯¹è±¡æˆ–数组") - } - } catch (e) { - freturn = true - } - - var arr = data.value.split(".") || [] - if (arr.length > 1) { - arr.pop() - var n = arr[0] - for (var i = 0, v; v = vmodels[i++];) { - if (v && v.hasOwnProperty(n)) { - var events = v[n].$events || {} - events[subscribers] = events[subscribers] || [] - events[subscribers].push(data) - break - } - } - } - var elem = data.element - elem.removeAttribute(data.name) - - data.sortedCallback = getBindingCallback(elem, "data-with-sorted", vmodels) - data.renderedCallback = getBindingCallback(elem, "data-" + type + "-rendered", vmodels) - var signature = generateID(type) - var comment = data.element = DOC.createComment(signature + ":end") - data.clone = DOC.createComment(signature) - hyperspace.appendChild(comment) - - if (type === "each" || type === "with") { - data.template = elem.innerHTML.trim() - avalon.clearHTML(elem).appendChild(comment) - } else { - data.template = elem.outerHTML.trim() - elem.parentNode.replaceChild(comment, elem) - } - data.template = avalon.parseHTML(data.template) - data.rollback = function () { - var elem = data.element - if (!elem) - return - bindingExecutors.repeat.call(data, "clear") - var parentNode = elem.parentNode - var content = data.template - var target = content.firstChild - parentNode.replaceChild(content, elem) - var start = data.$with - start && start.parentNode && start.parentNode.removeChild(start) - target = data.element = data.type === "repeat" ? target : parentNode - } - if (freturn) { - return - } - data.handler = bindingExecutors.repeat - data.$outer = {} - var check0 = "$key" - var check1 = "$val" - if (Array.isArray($repeat)) { - $repeat.$map[data.param || "el"] = 1 - check0 = "$first" - check1 = "$last" - } - for (i = 0; v = vmodels[i++];) { - if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) { - data.$outer = v - break - } - } - var $events = $repeat.$events - var $list = ($events || {})[subscribers] - if ($list && avalon.Array.ensure($list, data)) { - addSubscribers(data, $list) - } - if (xtype === "object") { - data.$with = true - var pool = !$events ? {} : $events.$withProxyPool || ($events.$withProxyPool = {}) - data.handler("append", $repeat, pool) - } else if ($repeat.length) { - data.handler("add", 0, $repeat.length) - } - } - - bindingExecutors.repeat = function (method, pos, el) { - if (method) { - var data = this, start, fragment - var end = data.element - var comments = getComments(data) - var parent = end.parentNode - var transation = hyperspace.cloneNode(false) - switch (method) { - case "add": //在posä½ç½®åŽæ·»åŠ el数组(pos为æ’å…¥ä½ç½®,el为è¦æ’入的个数) - var n = pos + el - var fragments = [] - var array = data.$repeat - for (var i = pos; i < n; i++) { - var proxy = array.$proxy[i] - proxy.$outer = data.$outer - shimController(data, transation, proxy, fragments) - } - parent.insertBefore(transation, comments[pos] || end) - for (i = 0; fragment = fragments[i++];) { - scanNodeArray(fragment.nodes, fragment.vmodels) - fragment.nodes = fragment.vmodels = null - } - break - case "del": //å°†posåŽçš„el个元素删掉(pos, el都是数字) - sweepNodes(comments[pos], comments[pos + el] || end) - break - case "clear": - start = comments[0] - if (start) { - sweepNodes(start, end) - } - break - case "move": - start = comments[0] - if (start) { - var signature = start.nodeValue - var rooms = [] - var room = [], - node - sweepNodes(start, end, function () { - room.unshift(this) - if (this.nodeValue === signature) { - rooms.unshift(room) - room = [] - } - }) - sortByIndex(rooms, pos) - while (room = rooms.shift()) { - while (node = room.shift()) { - transation.appendChild(node) - } - } - parent.insertBefore(transation, end) - } - break - case "append": //å°†pos的键值对从el中å–出(pos为一个普通对象,el为预先生æˆå¥½çš„代ç†VM对象池) - var pool = el - var keys = [] - fragments = [] - for (var key in pos) { //得到所有键å - if (pos.hasOwnProperty(key) && key !== "hasOwnProperty") { - keys.push(key) - } - } - if (data.sortedCallback) { //å¦‚æžœæœ‰å›žè°ƒï¼Œåˆ™è®©å®ƒä»¬æŽ’åº - var keys2 = data.sortedCallback.call(parent, keys) - if (keys2 && Array.isArray(keys2) && keys2.length) { - keys = keys2 - } - } - for (i = 0; key = keys[i++];) { - if (key !== "hasOwnProperty") { - if (!pool[key]) { - pool[key] = withProxyAgent(key, data) - } - shimController(data, transation, pool[key], fragments) - } - } - var comment = data.$with = data.clone - parent.insertBefore(comment, end) - parent.insertBefore(transation, end) - for (i = 0; fragment = fragments[i++];) { - scanNodeArray(fragment.nodes, fragment.vmodels) - fragment.nodes = fragment.vmodels = null - } - break - } - if (method === "clear") - method = "del" - var callback = data.renderedCallback || noop, - args = arguments - checkScan(parent, function () { - callback.apply(parent, args) - if (parent.oldValue && parent.tagName === "SELECT") { //fix #503 - avalon(parent).val(parent.oldValue.split(",")) - } - }, NaN) - } - } - - "with,each".replace(rword, function (name) { - bindingHandlers[name] = bindingHandlers.repeat - }) - - function shimController(data, transation, proxy, fragments) { - var content = data.template.cloneNode(true) - var nodes = avalon.slice(content.childNodes) - if (!data.$with) { - content.insertBefore(data.clone.cloneNode(false), content.firstChild) - } - transation.appendChild(content) - var nv = [proxy].concat(data.vmodels) - var fragment = { - nodes: nodes, - vmodels: nv - } - fragments.push(fragment) - } - - function getComments(data) { - var end = data.element - var signature = end.nodeValue.replace(":end", "") - var node = end.previousSibling - var array = [] - while (node) { - if (node.nodeValue === signature) { - array.unshift(node) - } - node = node.previousSibling - } - return array - } - - -//移除掉start与end之间的节点(ä¿ç•™end) - function sweepNodes(start, end, callback) { - while (true) { - var node = end.previousSibling - if (!node) - break - node.parentNode.removeChild(node) - callback && callback.call(node) - if (node === start) { - break - } - } - } - -// 为ms-each,ms-with, ms-repeat会创建一个代ç†VM, -// 通过它们ä¿æŒä¸€ä¸ªä¸‹ä¸Šæ–‡ï¼Œè®©ç”¨æˆ·èƒ½è°ƒç”¨$index,$first,$last,$remove,$key,$val,$outer等属性与方法 -// 所有代ç†VM的产生,消费,收集,存放通过xxxProxyFactory,xxxProxyAgent, recycleProxies,xxxProxyPool实现 - var eachProxyPool = [] - var withProxyPool = [] - - function eachProxyFactory() { - var source = { - $index: 0, - $first: false, - $last: false, - $map: {}, - $host: [], - $outer: {}, - $remove: avalon.noop, - el: { - get: function () { - var e = this.$events - var array = e.$index - e.$index = e.el //#817 通过$index为el收集ä¾èµ– - try { - return this.$host[this.$index] - } finally { - e.$index = array - } - }, - set: function (val) { - this.$host.set(this.$index, val) - } - } - } - - var second = { - $last: 1, - $first: 1, - $index: 1 - } - var proxy = modelFactory(source, second) - proxy.$id = generateID("$proxy$each") - return proxy - } - - function eachProxyAgent(index, host) { - var proxy = eachProxyPool.shift() - if (!proxy) { - proxy = eachProxyFactory() - } - var last = host.length - 1 - proxy.$index = index - proxy.$first = index === 0 - proxy.$last = index === last - proxy.$map = host.$map - proxy.$host = host - proxy.$remove = function () { - return host.removeAt(proxy.$index) - } - return proxy - } - - function withProxyFactory() { - var proxy = modelFactory({ - $key: "", - $outer: {}, - $host: {}, - $val: { - get: function () { - return this.$host[this.$key] - }, - set: function (val) { - this.$host[this.$key] = val - } - } - }, { - $val: 1 - }) - proxy.$id = generateID("$proxy$with") - return proxy - } - - function withProxyAgent(key, data) { - var proxy = withProxyPool.pop() - if (!proxy) { - proxy = withProxyFactory() - } - var host = data.$repeat - proxy.$key = key - proxy.$host = host - proxy.$outer = data.$outer - if (host.$events) { - proxy.$events.$val = host.$events[key] - } else { - proxy.$events = {} - } - return proxy - } - - function recycleProxies(proxies, type) { - var proxyPool = type === "each" ? eachProxyPool : withProxyPool - avalon.each(proxies, function (key, proxy) { - if (proxy.$events) { - for (var i in proxy.$events) { - if (Array.isArray(proxy.$events[i])) { - proxy.$events[i].forEach(function (data) { - if (typeof data === "object") - disposeData(data) - }) // jshint ignore:line - proxy.$events[i].length = 0 - } - } - proxy.$host = proxy.$outer = {} - if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) { - proxyPool.pop() - } - } - }) - if (type === "each") - proxies.length = 0 - } - - /********************************************************************* - * å„ç§æŒ‡ä»¤ * - **********************************************************************/ -//ms-skip绑定已ç»åœ¨scanTag 方法中实现 -// bindingHandlers.text 定义在if.js - bindingExecutors.text = function (val, elem) { - val = val == null ? "" : val //ä¸åœ¨é¡µé¢ä¸Šæ˜¾ç¤ºundefined null - if (elem.nodeType === 3) { //绑定在文本节点上 - try { //IE对游离于DOM树外的节点赋值会报错 - elem.data = val - } catch (e) { - } - } else { //绑定在特性节点上 - elem.textContent = val - } - } - function parseDisplay(nodeName, val) { - //用于å–得此类标签的默认display值 - var key = "_" + nodeName - if (!parseDisplay[key]) { - var node = DOC.createElement(nodeName) - root.appendChild(node) - if (W3C) { - val = getComputedStyle(node, null).display - } else { - val = node.currentStyle.display - } - root.removeChild(node) - parseDisplay[key] = val - } - return parseDisplay[key] - } - - avalon.parseDisplay = parseDisplay - - bindingHandlers.visible = function (data, vmodels) { - var elem = avalon(data.element) - var display = elem.css("display") - if (display === "none") { - var style = elem[0].style - var has = /visibility/i.test(style.cssText) - var visible = elem.css("visibility") - style.display = "" - style.visibility = "hidden" - display = elem.css("display") - if (display === "none") { - display = parseDisplay(elem[0].nodeName) - } - style.visibility = has ? visible : "" - } - data.display = display - parseExprProxy(data.value, vmodels, data) - } - - bindingExecutors.visible = function (val, elem, data) { - elem.style.display = val ? data.display : "none" - } - bindingHandlers.widget = function (data, vmodels) { - var args = data.value.match(rword) - var elem = data.element - var widget = args[0] - var id = args[1] - if (!id || id === "$") { //没有定义或为$时,å–组件å+éšæœºæ•° - id = generateID(widget) - } - var optName = args[2] || widget //没有定义,å–组件å - var constructor = avalon.ui[widget] - if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname" - vmodels = elem.vmodels || vmodels - for (var i = 0, v; v = vmodels[i++];) { - if (v.hasOwnProperty(optName) && typeof v[optName] === "object") { - var vmOptions = v[optName] - vmOptions = vmOptions.$model || vmOptions - break - } - } - if (vmOptions) { - var wid = vmOptions[widget + "Id"] - if (typeof wid === "string") { - log("warning!ä¸å†æ”¯æŒ" + widget + "Id") - id = wid - } - } - //抽å–data-tooltip-textã€data-tooltip-attr属性,组æˆä¸€ä¸ªé…置对象 - var widgetData = avalon.getWidgetData(elem, widget) - data.value = [widget, id, optName].join(",") - data[widget + "Id"] = id - data.evaluator = noop - elem.msData["ms-widget-id"] = id - var options = data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData) - elem.removeAttribute("ms-widget") - var vmodel = constructor(elem, data, vmodels) || {} //防止组件ä¸è¿”回VM - if (vmodel.$id) { - avalon.vmodels[id] = vmodel - createSignalTower(elem, vmodel) - try { - vmodel.$init(function () { - avalon.scan(elem, [vmodel].concat(vmodels)) - if (typeof options.onInit === "function") { - options.onInit.call(elem, vmodel, options, vmodels) - } - }) - } catch (e) { - } - data.rollback = function () { - try { - vmodel.widgetElement = null - vmodel.$remove() - } catch (e) { - } - elem.msData = {} - delete avalon.vmodels[vmodel.$id] - } - addSubscribers(data, widgetList) - if (window.chrome) { - elem.addEventListener("DOMNodeRemovedFromDocument", function () { - setTimeout(removeSubscribers) - }) - } - } else { - avalon.scan(elem, vmodels) - } - } else if (vmodels.length) { //如果该组件还没有加载,那么ä¿å­˜å½“å‰çš„vmodels - elem.vmodels = vmodels - } - } - var widgetList = [] -//ä¸å­˜åœ¨ bindingExecutors.widget - /********************************************************************* - * 自带过滤器 * - **********************************************************************/ - var rscripts = /]*>([\S\s]*?)<\/script\s*>/gim - var ron = /\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g - var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig - var rsanitize = { - a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig, - img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig, - form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig - } - var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g - var rnoalphanumeric = /([^\#-~| |!])/g; - - function numberFormat(number, decimals, point, thousands) { - //form http://phpjs.org/functions/number_format/ - //number 必需,è¦æ ¼å¼åŒ–çš„æ•°å­— - //decimals å¯é€‰ï¼Œè§„定多少个å°æ•°ä½ã€‚ - //point å¯é€‰ï¼Œè§„定用作å°æ•°ç‚¹çš„字符串(默认为 . )。 - //thousands å¯é€‰ï¼Œè§„定用作åƒä½åˆ†éš”符的字符串(默认为 , ),如果设置了该å‚数,那么所有其他å‚数都是必需的。 - number = (number + '') - .replace(/[^0-9+\-Ee.]/g, '') - var n = !isFinite(+number) ? 0 : +number, - prec = !isFinite(+decimals) ? 3 : Math.abs(decimals), - sep = thousands || ",", - dec = point || ".", - s = '', - toFixedFix = function (n, prec) { - var k = Math.pow(10, prec) - return '' + (Math.round(n * k) / k) - .toFixed(prec) - } - // Fix for IE parseFloat(0.55).toFixed(0) = 0; - s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)) - .split('.') - if (s[0].length > 3) { - s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep) - } - if ((s[1] || '') - .length < prec) { - s[1] = s[1] || '' - s[1] += new Array(prec - s[1].length + 1) - .join('0') - } - return s.join(dec) - } - - - var filters = avalon.filters = { - uppercase: function (str) { - return str.toUpperCase() - }, - lowercase: function (str) { - return str.toLowerCase() - }, - truncate: function (str, length, truncation) { - //length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串 - length = length || 30 - truncation = truncation === void(0) ? "..." : truncation - return str.length > length ? str.slice(0, length - truncation.length) + truncation : String(str) - }, - $filter: function (val) { - for (var i = 1, n = arguments.length; i < n; i++) { - var array = arguments[i] - var fn = avalon.filters[array.shift()] - if (typeof fn === "function") { - var arr = [val].concat(array) - val = fn.apply(null, arr) - } - } - return val - }, - camelize: camelize, - //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet - // chrome - // chrome - // IE67chrome - // IE67chrome - // IE67chrome - sanitize: function (str) { - return str.replace(rscripts, "").replace(ropen, function (a, b) { - var match = a.toLowerCase().match(/<(\w+)\s/) - if (match) { //处ç†a标签的href属性,img标签的src属性,form标签的action属性 - var reg = rsanitize[match[1]] - if (reg) { - a = a.replace(reg, function (s, name, value) { - var quote = value.charAt(0) - return name + "=" + quote + "javascript:void(0)" + quote// jshint ignore:line - }) - } - } - return a.replace(ron, " ").replace(/\s+/g, " ") //移除onXXX事件 - }) - }, - escape: function (str) { - //将字符串ç»è¿‡ str 转义得到适åˆåœ¨é¡µé¢ä¸­æ˜¾ç¤ºçš„内容, ä¾‹å¦‚æ›¿æ¢ < 为 < - return String(str). - replace(/&/g, '&'). - replace(rsurrogate, function (value) { - var hi = value.charCodeAt(0) - var low = value.charCodeAt(1) - return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';' - }). - replace(rnoalphanumeric, function (value) { - return '&#' + value.charCodeAt(0) + ';' - }). - replace(//g, '>') - }, - currency: function (amount, symbol, fractionSize) { - return (symbol || "\uFFE5") + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2) - }, - number: numberFormat - } - /* - 'yyyy': 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010) - 'yy': 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) - 'y': 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199) - 'MMMM': Month in year (January-December) - 'MMM': Month in year (Jan-Dec) - 'MM': Month in year, padded (01-12) - 'M': Month in year (1-12) - 'dd': Day in month, padded (01-31) - 'd': Day in month (1-31) - 'EEEE': Day in Week,(Sunday-Saturday) - 'EEE': Day in Week, (Sun-Sat) - 'HH': Hour in day, padded (00-23) - 'H': Hour in day (0-23) - 'hh': Hour in am/pm, padded (01-12) - 'h': Hour in am/pm, (1-12) - 'mm': Minute in hour, padded (00-59) - 'm': Minute in hour (0-59) - 'ss': Second in minute, padded (00-59) - 's': Second in minute (0-59) - 'a': am/pm marker - 'Z': 4 digit (+sign) representation of the timezone offset (-1200-+1200) - format string can also be one of the following predefined localizable formats: - - 'medium': equivalent to 'MMM d, y h:mm:ss a' for en_US locale (e.g. Sep 3, 2010 12:05:08 pm) - 'short': equivalent to 'M/d/yy h:mm a' for en_US locale (e.g. 9/3/10 12:05 pm) - 'fullDate': equivalent to 'EEEE, MMMM d,y' for en_US locale (e.g. Friday, September 3, 2010) - 'longDate': equivalent to 'MMMM d, y' for en_US locale (e.g. September 3, 2010 - 'mediumDate': equivalent to 'MMM d, y' for en_US locale (e.g. Sep 3, 2010) - 'shortDate': equivalent to 'M/d/yy' for en_US locale (e.g. 9/3/10) - 'mediumTime': equivalent to 'h:mm:ss a' for en_US locale (e.g. 12:05:08 pm) - 'shortTime': equivalent to 'h:mm a' for en_US locale (e.g. 12:05 pm) - */ - new function () {// jshint ignore:line - function toInt(str) { - return parseInt(str, 10) || 0 - } - - function padNumber(num, digits, trim) { - var neg = "" - if (num < 0) { - neg = '-' - num = -num - } - num = "" + num - while (num.length < digits) - num = "0" + num - if (trim) - num = num.substr(num.length - digits) - return neg + num - } - - function dateGetter(name, size, offset, trim) { - return function (date) { - var value = date["get" + name]() - if (offset > 0 || value > -offset) - value += offset - if (value === 0 && offset === -12) { - value = 12 - } - return padNumber(value, size, trim) - } - } - - function dateStrGetter(name, shortForm) { - return function (date, formats) { - var value = date["get" + name]() - var get = (shortForm ? ("SHORT" + name) : name).toUpperCase() - return formats[get][value] - } - } - - function timeZoneGetter(date) { - var zone = -1 * date.getTimezoneOffset() - var paddedZone = (zone >= 0) ? "+" : "" - paddedZone += padNumber(Math[zone > 0 ? "floor" : "ceil"](zone / 60), 2) + padNumber(Math.abs(zone % 60), 2) - return paddedZone - } - - //å–得上åˆä¸‹åˆ - - function ampmGetter(date, formats) { - return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1] - } - - var DATE_FORMATS = { - yyyy: dateGetter("FullYear", 4), - yy: dateGetter("FullYear", 2, 0, true), - y: dateGetter("FullYear", 1), - MMMM: dateStrGetter("Month"), - MMM: dateStrGetter("Month", true), - MM: dateGetter("Month", 2, 1), - M: dateGetter("Month", 1, 1), - dd: dateGetter("Date", 2), - d: dateGetter("Date", 1), - HH: dateGetter("Hours", 2), - H: dateGetter("Hours", 1), - hh: dateGetter("Hours", 2, -12), - h: dateGetter("Hours", 1, -12), - mm: dateGetter("Minutes", 2), - m: dateGetter("Minutes", 1), - ss: dateGetter("Seconds", 2), - s: dateGetter("Seconds", 1), - sss: dateGetter("Milliseconds", 3), - EEEE: dateStrGetter("Day"), - EEE: dateStrGetter("Day", true), - a: ampmGetter, - Z: timeZoneGetter - } - var rdateFormat = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/ - var raspnetjson = /^\/Date\((\d+)\)\/$/ - filters.date = function (date, format) { - var locate = filters.date.locate, - text = "", - parts = [], - fn, match - format = format || "mediumDate" - format = locate[format] || format - if (typeof date === "string") { - if (/^\d+$/.test(date)) { - date = toInt(date) - } else if (raspnetjson.test(date)) { - date = +RegExp.$1 - } else { - var trimDate = date.trim() - var dateArray = [0, 0, 0, 0, 0, 0, 0] - var oDate = new Date(0) - //å–得年月日 - trimDate = trimDate.replace(/^(\d+)\D(\d+)\D(\d+)/, function (_, a, b, c) { - var array = c.length === 4 ? [c, a, b] : [a, b, c] - dateArray[0] = toInt(array[0]) //å¹´ - dateArray[1] = toInt(array[1]) - 1 //月 - dateArray[2] = toInt(array[2]) //æ—¥ - return "" - }) - var dateSetter = oDate.setFullYear - var timeSetter = oDate.setHours - trimDate = trimDate.replace(/[T\s](\d+):(\d+):?(\d+)?\.?(\d)?/, function (_, a, b, c, d) { - dateArray[3] = toInt(a) //å°æ—¶ - dateArray[4] = toInt(b) //分钟 - dateArray[5] = toInt(c) //秒 - if (d) { //毫秒 - dateArray[6] = Math.round(parseFloat("0." + d) * 1000) - } - return "" - }) - var tzHour = 0 - var tzMin = 0 - trimDate = trimDate.replace(/Z|([+-])(\d\d):?(\d\d)/, function (z, symbol, c, d) { - dateSetter = oDate.setUTCFullYear - timeSetter = oDate.setUTCHours - if (symbol) { - tzHour = toInt(symbol + c) - tzMin = toInt(symbol + d) - } - return "" - }) - - dateArray[3] -= tzHour - dateArray[4] -= tzMin - dateSetter.apply(oDate, dateArray.slice(0, 3)) - timeSetter.apply(oDate, dateArray.slice(3)) - date = oDate - } - } - if (typeof date === "number") { - date = new Date(date) - } - if (avalon.type(date) !== "date") { - return - } - while (format) { - match = rdateFormat.exec(format) - if (match) { - parts = parts.concat(match.slice(1)) - format = parts.pop() - } else { - parts.push(format) - format = null - } - } - parts.forEach(function (value) { - fn = DATE_FORMATS[value] - text += fn ? fn(date, locate) : value.replace(/(^'|'$)/g, "").replace(/''/g, "'") - }) - return text - } - var locate = { - AMPMS: { - 0: "上åˆ", - 1: "下åˆ" - }, - DAY: { - 0: "星期日", - 1: "星期一", - 2: "星期二", - 3: "星期三", - 4: "星期四", - 5: "星期五", - 6: "星期六" - }, - MONTH: { - 0: "1月", - 1: "2月", - 2: "3月", - 3: "4月", - 4: "5月", - 5: "6月", - 6: "7月", - 7: "8月", - 8: "9月", - 9: "10月", - 10: "11月", - 11: "12月" - }, - SHORTDAY: { - "0": "周日", - "1": "周一", - "2": "周二", - "3": "周三", - "4": "周四", - "5": "周五", - "6": "周六" - }, - fullDate: "yå¹´M月dæ—¥EEEE", - longDate: "yå¹´M月dæ—¥", - medium: "yyyy-M-d H:mm:ss", - mediumDate: "yyyy-M-d", - mediumTime: "H:mm:ss", - "short": "yy-M-d ah:mm", - shortDate: "yy-M-d", - shortTime: "ah:mm" - } - locate.SHORTMONTH = locate.MONTH - filters.date.locate = locate - }// jshint ignore:line - /********************************************************************* - * AMD加载器 * - **********************************************************************/ -//https://www.devbridge.com/articles/understanding-amd-requirejs/ -//http://maxogden.com/nested-dependencies.html - var modules = avalon.modules = { - "domReady!": { - exports: avalon, - state: 3 - }, - "avalon": { - exports: avalon, - state: 4 - } - } -//Object(modules[id]).state拥有如下值 -// undefined 没有定义 -// 1(send) å·²ç»å‘出请求 -// 2(loading) å·²ç»è¢«æ‰§è¡Œä½†è¿˜æ²¡æœ‰æ‰§è¡Œå®Œæˆï¼Œåœ¨è¿™ä¸ªé˜¶æ®µdefine方法会被执行 -// 3(loaded) 执行完毕,通过onload/onreadystatechange回调判定,在这个阶段checkDeps方法会执行 -// 4(execute) å…¶ä¾èµ–也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行 - modules.exports = modules.avalon - - new function () {// jshint ignore:line - var loadings = [] //正在加载中的模å—列表 - var factorys = [] //放置define方法的factory函数 - var rjsext = /\.js$/i - - function makeRequest(name, config) { -//1. 去掉资æºå‰ç¼€ - var res = "js" - name = name.replace(/^(\w+)\!/, function (a, b) { - res = b - return "" - }) - if (res === "ready") { - log("debug: ready!å·²ç»è¢«åºŸå¼ƒï¼Œè¯·ä½¿ç”¨domReady!") - res = "domReady" - } -//2. 去掉querystring, hash - var query = "" - name = name.replace(rquery, function (a) { - query = a - return "" - }) - //3. 去掉扩展å - var suffix = "." + res - var ext = /js|css/.test(suffix) ? suffix : "" - name = name.replace(/\.[a-z0-9]+$/g, function (a) { - if (a === suffix) { - ext = a - return "" - } else { - return a - } - }) - var req = avalon.mix({ - query: query, - ext: ext, - res: res, - name: name, - toUrl: toUrl - }, config) - req.toUrl(name) - return req - } - - function fireRequest(req) { - var name = req.name - var res = req.res - //1. 如果该模å—å·²ç»å‘出请求,直接返回 - var module = modules[name] - var urlNoQuery = name && req.urlNoQuery - if (module && module.state >= 1) { - return name - } - module = modules[urlNoQuery] - if (module && module.state >= 3) { - innerRequire(module.deps || [], module.factory, urlNoQuery) - return urlNoQuery - } - if (name && !module) { - module = modules[urlNoQuery] = { - id: urlNoQuery, - state: 1 //send - } - var wrap = function (obj) { - resources[res] = obj - obj.load(name, req, function (a) { - if (arguments.length && a !== void 0) { - module.exports = a - } - module.state = 4 - checkDeps() - }) - } - - if (!resources[res]) { - innerRequire([res], wrap) - } else { - wrap(resources[res]) - } - } - return name ? urlNoQuery : res + "!" - } - -//核心API之一 require - var requireQueue = [] - var isUserFirstRequire = false - innerRequire = avalon.require = function (array, factory, parentUrl, defineConfig) { - if (!isUserFirstRequire) { - requireQueue.push(avalon.slice(arguments)) - if (arguments.length <= 2) { - isUserFirstRequire = true - var queue = requireQueue.splice(0, requireQueue.length), args - while (args = queue.shift()) { - innerRequire.apply(null, args) - } - } - return - } - - if (!Array.isArray(array)) { - avalon.error("require方法的第一个å‚数应为数组 " + array) - } - var deps = [] // 放置所有ä¾èµ–项的完整路径 - var uniq = createMap() - var id = parentUrl || "callback" + setTimeout("1")// jshint ignore:line - defineConfig = defineConfig || createMap() - defineConfig.baseUrl = kernel.baseUrl - var isBuilt = !!defineConfig.built - if (parentUrl) { - defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf("/")) - defineConfig.mapUrl = parentUrl.replace(rjsext, "") - } - if (isBuilt) { - var req = makeRequest(defineConfig.defineName, defineConfig) - id = req.urlNoQuery - } else { - array.forEach(function (name) { - var req = makeRequest(name, defineConfig) - var url = fireRequest(req) //加载资æºï¼Œå¹¶è¿”回该资æºçš„å®Œæ•´åœ°å€ - if (url) { - if (!uniq[url]) { - deps.push(url) - uniq[url] = "å¸å¾’正美" //åŽ»é‡ - } - } - }) - } - - var module = modules[id] - if (!module || module.state !== 4) { - modules[id] = { - id: id, - deps: isBuilt ? array.concat() : deps, - factory: factory || noop, - state: 3 - } - } - if (!module) { - //如果此模å—是定义在å¦ä¸€ä¸ªJS文件中, 那必须等该文件加载完毕, æ‰èƒ½æ”¾åˆ°æ£€æµ‹åˆ—队中 - loadings.push(id) - } - checkDeps() - } - -//核心API之二 require - innerRequire.define = function (name, deps, factory) { //模å—å,ä¾èµ–列表,模å—本身 - if (typeof name !== "string") { - factory = deps - deps = name - name = "anonymous" - } - if (!Array.isArray(deps)) { - factory = deps - deps = [] - } - var config = { - built: !isUserFirstRequire, //用r.js打包åŽ,所有define会放到requirejsä¹‹å‰ - defineName: name - } - var args = [deps, factory, config] - factory.require = function (url) { - args.splice(2, 0, url) - if (modules[url]) { - modules[url].state = 3 //loaded - var isCycle = false - try { - isCycle = checkCycle(modules[url].deps, url) - } catch (e) { - } - if (isCycle) { - avalon.error(url + "模å—与之å‰çš„模å—存在循环ä¾èµ–,请ä¸è¦ç›´æŽ¥ç”¨script标签引入" + url + "模å—") - } - } - delete factory.require //释放内存 - innerRequire.apply(null, args) //0,1,2 --> 1,2,0 - } -//æ ¹æ®æ ‡å‡†,所有éµå¾ªW3C标准的æµè§ˆå™¨,script标签会按标签的出现顺åºæ‰§è¡Œã€‚ -//è€çš„æµè§ˆå™¨ä¸­ï¼ŒåŠ è½½ä¹Ÿæ˜¯æŒ‰é¡ºåºçš„:一个文件下载完æˆåŽï¼Œæ‰å¼€å§‹ä¸‹è½½ä¸‹ä¸€ä¸ªæ–‡ä»¶ã€‚ -//较新的æµè§ˆå™¨ä¸­ï¼ˆIE8+ ã€FireFox3.5+ ã€Chrome4+ ã€Safari4+),为了å‡å°è¯·æ±‚时间以优化体验, -//下载å¯ä»¥æ˜¯å¹¶è¡Œçš„,但是执行顺åºè¿˜æ˜¯æŒ‰ç…§æ ‡ç­¾å‡ºçŽ°çš„顺åºã€‚ -//但如果script标签是动æ€æ’入的, 就未必按照先请求先执行的原则了,目测åªæœ‰firefoxéµå®ˆ -//唯一比较一致的是,IE10+åŠå…¶ä»–标准æµè§ˆå™¨,一旦开始解æžè„šæœ¬, 就会一直堵在那里,直接脚本解æžå®Œæ¯• -//亦å³ï¼Œå…ˆè¿›å…¥loading阶段的script标签(模å—)必然会先进入loaded阶段 - var url = config.built ? "unknown" : getCurrentScript() - if (url) { - var module = modules[url] - if (module) { - module.state = 2 - } - factory.require(url) - } else {//åˆå¹¶å‰åŽçš„safari,åˆå¹¶åŽçš„IE6-9走此分支 - factorys.push(factory) - } - } -//核心API之三 require.config(settings) - innerRequire.config = kernel - //核心API之四 define.amd 标识其符åˆAMD规范 - innerRequire.define.amd = modules - - //==========================对用户é…置项进行å†åŠ å·¥========================== - var allpaths = kernel["orig.paths"] = createMap() - var allmaps = kernel["orig.map"] = createMap() - var allpackages = kernel["packages"] = [] - var allargs = kernel["orig.args"] = createMap() - avalon.mix(plugins, { - paths: function (hash) { - avalon.mix(allpaths, hash) - kernel.paths = makeIndexArray(allpaths) - }, - map: function (hash) { - avalon.mix(allmaps, hash) - var list = makeIndexArray(allmaps, 1, 1) - avalon.each(list, function (_, item) { - item.val = makeIndexArray(item.val) - }) - kernel.map = list - }, - packages: function (array) { - array = array.concat(allpackages) - var uniq = createMap() - var ret = [] - for (var i = 0, pkg; pkg = array[i++];) { - pkg = typeof pkg === "string" ? {name: pkg} : pkg - var name = pkg.name - if (!uniq[name]) { - var url = joinPath(pkg.location || name, pkg.main || "main") - url = url.replace(rjsext, "") - ret.push(pkg) - uniq[name] = pkg.location = url - pkg.reg = makeMatcher(name) - } - } - kernel.packages = ret.sort() - }, - urlArgs: function (hash) { - if (typeof hash === "string") { - hash = {"*": hash} - } - avalon.mix(allargs, hash) - kernel.urlArgs = makeIndexArray(allargs, 1) - }, - baseUrl: function (url) { - if (!isAbsUrl(url)) { - var baseElement = head.getElementsByTagName("base")[0] - if (baseElement) { - head.removeChild(baseElement) - } - var node = DOC.createElement("a") - node.href = url - url = node.href - if (baseElement) { - head.insertBefore(baseElement, head.firstChild) - } - } - if (url.length > 3) - kernel.baseUrl = url - }, - shim: function (obj) { - for (var i in obj) { - var value = obj[i] - if (Array.isArray(value)) { - value = obj[i] = { - deps: value - } - } - if (!value.exportsFn && (value.exports || value.init)) { - value.exportsFn = makeExports(value) - } - } - kernel.shim = obj - } - - }) - - - //==============================内部方法================================= - function checkCycle(deps, nick) { - //检测是å¦å­˜åœ¨å¾ªçŽ¯ä¾èµ– - for (var i = 0, id; id = deps[i++];) { - if (modules[id].state !== 4 && - (id === nick || checkCycle(modules[id].deps, nick))) { - return true - } - } - } - - function checkFail(node, onError) { - var id = trimQuery(node.src) //检测是å¦æ­»é“¾ - node.onload = node.onerror = null - if (onError) { - setTimeout(function () { - head.removeChild(node) - node = null // 处ç†æ—§å¼IE下的循环引用问题 - }) - log("debug: 加载 " + id + " 失败" + onError + " " + (!modules[id].state)) - } else { - return true - } - } - - function checkDeps() { - //检测此JS模å—çš„ä¾èµ–是å¦éƒ½å·²å®‰è£…完毕,是则安装自身 - loop: for (var i = loadings.length, id; id = loadings[--i];) { - var obj = modules[id], - deps = obj.deps - if (!deps) - continue - for (var j = 0, key; key = deps[j]; j++) { - if (Object(modules[key]).state !== 4) { - continue loop - } - } - //如果deps是空对象或者其ä¾èµ–的模å—的状æ€éƒ½æ˜¯2 - if (obj.state !== 4) { - loadings.splice(i, 1) //必须先移除å†å®‰è£…,防止在IE下DOM树建完åŽæ‰‹åŠ¨åˆ·æ–°é¡µé¢ï¼Œä¼šå¤šæ¬¡æ‰§è¡Œå®ƒ - fireFactory(obj.id, obj.deps, obj.factory) - checkDeps() //如果æˆåŠŸ,则å†æ‰§è¡Œä¸€æ¬¡,以防有些模å—就差本模å—没有安装好 - } - } - } - - function loadJS(url, id, callback) { - //通过scriptèŠ‚ç‚¹åŠ è½½ç›®æ ‡æ¨¡å— - var node = DOC.createElement("script") - node.className = subscribers //让getCurrentScriptåªå¤„ç†ç±»å为subscribersçš„script节点 - node.onload = function () { - var factory = factorys.pop() - factory && factory.require(id) - if (callback) { - callback() - } - log("debug: å·²æˆåŠŸåŠ è½½ " + url) - id && loadings.push(id) - checkDeps() - } - node.onerror = function () { - checkFail(node, true) - } - - head.insertBefore(node, head.firstChild) //chrome下第二个å‚æ•°ä¸èƒ½ä¸ºnull - node.src = url //æ’入到head的第一个节点å‰ï¼Œé˜²æ­¢IE6下head标签没闭åˆå‰ä½¿ç”¨appendChild抛错 - log("debug: 正准备加载 " + url) //æ›´é‡è¦çš„是IE6下å¯ä»¥æ”¶çª„getCurrentScript的寻找范围 - } - - var resources = innerRequire.plugins = { - //三大常用资æºæ’件 js!, css!, text!, ready! - ready: { - load: noop - }, - js: { - load: function (name, req, onLoad) { - var url = req.url - var id = req.urlNoQuery - var shim = kernel.shim[name.replace(rjsext, "")] - if (shim) { //shim机制 - innerRequire(shim.deps || [], function () { - var args = avalon.slice(arguments) - loadJS(url, id, function () { - onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0) - }) - }) - } else { - loadJS(url, id) - } - } - }, - css: { - load: function (name, req, onLoad) { - var url = req.url - head.insertAdjacentHTML("afterBegin", '') - log("debug: å·²æˆåŠŸåŠ è½½ " + url) - onLoad() - } - }, - text: { - load: function (name, req, onLoad) { - var url = req.url - var xhr = getXHR() - xhr.onload = function () { - var status = xhr.status; - if (status > 399 && status < 600) { - avalon.error(url + " 对应资æºä¸å­˜åœ¨æˆ–æ²¡æœ‰å¼€å¯ CORS") - } else { - log("debug: å·²æˆåŠŸåŠ è½½ " + url) - onLoad(xhr.responseText) - } - } - xhr.open("GET", url, true) - if ("withCredentials" in xhr) {//这是处ç†è·¨åŸŸ - xhr.withCredentials = true - } - xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")//告诉åŽç«¯è¿™æ˜¯AJAX请求 - xhr.send() - log("debug: 正准备加载 " + url) - } - } - } - innerRequire.checkDeps = checkDeps - - var rquery = /(\?[^#]*)$/ - - function trimQuery(url) { - return (url || "").replace(rquery, "") - } - - function isAbsUrl(path) { - //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative - return /^(?:[a-z]+:)?\/\//i.test(String(path)) - } - - - function getCurrentScript() { - // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js - var stack - try { - a.b.c() //强制报错,以便æ•èŽ·e.stack - } catch (e) { //safari5çš„sourceURL,firefoxçš„fileName,它们的效果与e.stackä¸ä¸€æ · - stack = e.stack - } - if (stack) { - /**e.stack最åŽä¸€è¡Œåœ¨æ‰€æœ‰æ”¯æŒçš„æµè§ˆå™¨å¤§è‡´å¦‚下: - *chrome23: - * at http://113.93.50.63/data.js:4:1 - *firefox17: - *@http://113.93.50.63/query.js:4 - *opera12:http://www.oldapps.com/opera.php?system=Windows_XP - *@http://113.93.50.63/data.js:4 - *IE10: - * at Global code (http://113.93.50.63/data.js:4:1) - * //firefox4+ å¯ä»¥ç”¨document.currentScript - */ - stack = stack.split(/[@ ]/g).pop() //å–得最åŽä¸€è¡Œ,最åŽä¸€ä¸ªç©ºæ ¼æˆ–@之åŽçš„部分 - stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉æ¢è¡Œç¬¦ - return trimQuery(stack.replace(/(:\d+)?:\d+$/i, "")) //去掉行å·ä¸Žæˆ–许存在的出错字符起始ä½ç½® - } - var nodes = head.getElementsByTagName("script") //åªåœ¨head标签中寻找 - for (var i = nodes.length, node; node = nodes[--i];) { - if (node.className === subscribers && node.readyState === "interactive") { - var url = node.src - return node.className = trimQuery(url) - } - } - } - - var rcallback = /^callback\d+$/ - - function fireFactory(id, deps, factory) { - var module = Object(modules[id]) - module.state = 4 - for (var i = 0, array = [], d; d = deps[i++];) { - if (d === "exports") { - var obj = module.exports || (module.exports = createMap()) - array.push(obj) - } else { - array.push(modules[d].exports) - } - } - try { - var ret = factory.apply(window, array) - } catch (e) { - log("执行[" + id + "]模å—çš„factory抛错: " + e) - } - if (ret !== void 0) { - module.exports = ret - } - if (rcallback.test(id)) { - delete modules[id] - } - delete module.factory - return ret - } - - function toUrl(id) { - if (id.indexOf(this.res + "!") === 0) { - id = id.slice(this.res.length + 1) //处ç†define("css!style",[], function(){})的情况 - } - var url = id - //1. 是å¦å‘½ä¸­pathsé…置项 - var usePath = 0 - var baseUrl = this.baseUrl - var rootUrl = this.parentUrl || baseUrl - eachIndexArray(id, kernel.paths, function (value, key) { - url = url.replace(key, value) - usePath = 1 - }) - //2. 是å¦å‘½ä¸­packagesé…置项 - if (!usePath) { - eachIndexArray(id, kernel.packages, function (value, key, item) { - url = url.replace(item.name, item.location) - }) - } - //3. 是å¦å‘½ä¸­mapé…置项 - if (this.mapUrl) { - eachIndexArray(this.mapUrl, kernel.map, function (array) { - eachIndexArray(url, array, function (mdValue, mdKey) { - url = url.replace(mdKey, mdValue) - rootUrl = baseUrl - }) - }) - } - var ext = this.ext - if (ext && usePath && url.slice(-ext.length) === ext) { - url = url.slice(0, -ext.length) - } - //4. 转æ¢ä¸ºç»å¯¹è·¯å¾„ - if (!isAbsUrl(url)) { - rootUrl = this.built || /^\w/.test(url) ? baseUrl : rootUrl - url = joinPath(rootUrl, url) - } - //5. 还原扩展å,query - var urlNoQuery = url + ext - url = urlNoQuery + this.query - //6. 处ç†urlArgs - eachIndexArray(id, kernel.urlArgs, function (value) { - url += (url.indexOf("?") === -1 ? "?" : "&") + value; - }) - this.url = url - return this.urlNoQuery = urlNoQuery - } - - function makeIndexArray(hash, useStar, part) { - //创建一个ç»è¿‡ç‰¹æ®Šç®—法排好åºçš„数组 - var index = hash2array(hash, useStar, part) - index.sort(descSorterByName) - return index - } - - function makeMatcher(prefix) { - return new RegExp('^' + prefix + '(/|$)') - } - - function makeExports(value) { - return function () { - var ret - if (value.init) { - ret = value.init.apply(window, arguments) - } - return ret || (value.exports && getGlobal(value.exports)) - } - } - - - function hash2array(hash, useStar, part) { - var array = []; - for (var key in hash) { - // if (hash.hasOwnProperty(key)) {//hash是由createMap创建没有hasOwnProperty - var item = { - name: key, - val: hash[key] - } - array.push(item) - item.reg = key === "*" && useStar ? /^/ : makeMatcher(key) - if (part && key !== "*") { - item.reg = new RegExp('\/' + key.replace(/^\//, "") + '(/|$)') - } - // } - } - return array - } - - function eachIndexArray(moduleID, array, matcher) { - array = array || [] - for (var i = 0, el; el = array[i++];) { - if (el.reg.test(moduleID)) { - matcher(el.val, el.name, el) - return false - } - } - } - - // æ ¹æ®å…ƒç´ çš„name项进行数组字符数逆åºçš„排åºå‡½æ•° - function descSorterByName(a, b) { - var aaa = a.name - var bbb = b.name - if (bbb === "*") { - return -1 - } - if (aaa === "*") { - return 1 - } - return bbb.length - aaa.length - } - - var rdeuce = /\/\w+\/\.\./ - - function joinPath(a, b) { - if (a.charAt(a.length - 1) !== "/") { - a += "/" - } - if (b.slice(0, 2) === "./") { //相对于兄弟路径 - return a + b.slice(2) - } - if (b.slice(0, 2) === "..") { //相对于父路径 - a += b - while (rdeuce.test(a)) { - a = a.replace(rdeuce, "") - } - return a - } - if (b.slice(0, 1) === "/") { - return a + b.slice(1) - } - return a + b - } - - function getGlobal(value) { - if (!value) { - return value - } - var g = window - value.split(".").forEach(function (part) { - g = g[part] - }) - return g - } - - var mainNode = DOC.scripts[DOC.scripts.length - 1] - var dataMain = mainNode.getAttribute("data-main") - if (dataMain) { - plugins.baseUrl(dataMain) - var href = kernel.baseUrl - kernel.baseUrl = href.slice(0, href.lastIndexOf("/") + 1) - loadJS(href.replace(rjsext, "") + ".js") - } else { - var loaderUrl = trimQuery(mainNode.src) - kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1) - } - }// jshint ignore:line - - /********************************************************************* - * DOMReady * - **********************************************************************/ - var readyList = [], isReady - var fireReady = function (fn) { - isReady = true - if (innerRequire) { - modules["domReady!"].state = 4 - innerRequire.checkDeps() - } - while (fn = readyList.shift()) { - fn(avalon) - } - } - - - if (DOC.readyState === "complete") { - setTimeout(fireReady) //如果在domReady之外加载 - } else { - DOC.addEventListener("DOMContentLoaded", fireReady) - } - window.addEventListener("load", fireReady) - avalon.ready = function (fn) { - if (!isReady) { - readyList.push(fn) - } else { - fn(avalon) - } - } - avalon.config({ - loader: true - }) - avalon.ready(function () { - avalon.scan(DOC.body) - }) - -// Register as a named AMD module, since avalon can be concatenated with other -// files that may use define, but not via a proper concatenation script that -// understands anonymous AMD modules. A named AMD is safest and most robust -// way to register. Lowercase avalon is used because AMD module names are -// derived from file names, and Avalon is normally delivered in a lowercase -// file name. Do this after creating the global so that if an AMD module wants -// to call noConflict to hide this version of avalon, it will work. - -// Note that for maximum portability, libraries that are not avalon should -// declare themselves as anonymous modules, and avoid setting a global if an -// AMD loader is present. avalon is a special case. For more information, see -// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon - if (typeof define === "function" && define.amd) { - define("avalon", [], function () { - return avalon - }) - } -// Map over avalon in case of overwrite - var _avalon = window.avalon - avalon.noConflict = function (deep) { - if (deep && window.avalon === avalon) { - window.avalon = _avalon - } - return avalon - } -// Expose avalon identifiers, even in AMD -// and CommonJS for browser emulators - if (noGlobal === void 0) { - window.avalon = avalon - } - - window._injectTer = function (code) { - return eval(code) - } - - return avalon - +/*================================================== + Copyright (c) 2013-2015 å¸å¾’正美 and other contributors + http://www.cnblogs.com/rubylouvre/ + https://github.com/RubyLouvre + http://weibo.com/jslouvre/ + + Released under the MIT license + avalon.modern.js 1.43 built in 2015.5.21 + support IE10+ and other browsers + ==================================================*/ +(function (global, factory) { + + if (typeof module === "object" && typeof module.exports === "object") { + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get avalon. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var avalon = require("avalon")(window); + module.exports = global.document ? factory(global, true) : function (w) { + if (!w.document) { + throw new Error("Avalon requires a window with a document") + } + return factory(w) + } + } else { + factory(global) + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function (window, noGlobal) { + + /********************************************************************* + * 全局å˜é‡åŠæ–¹æ³• * + **********************************************************************/ + var expose = Date.now() +//http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function + var DOC = window.document + var head = DOC.head //HEAD元素 + head.insertAdjacentHTML("afterBegin", '') + var ifGroup = head.firstChild + + function log() { + if (avalon.config.debug) { +// http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log + console.log.apply(console, arguments) + } + } + + /** + * Creates a new object without a prototype. This object is useful for lookup without having to + * guard against prototypically inherited properties via hasOwnProperty. + * + * Related micro-benchmarks: + * - http://jsperf.com/object-create2 + * - http://jsperf.com/proto-map-lookup/2 + * - http://jsperf.com/for-in-vs-object-keys2 + */ + function createMap() { + return Object.create(null) + } + + var subscribers = "$" + expose + var otherRequire = window.require + var otherDefine = window.define + var innerRequire + var stopRepeatAssign = false + var rword = /[^, ]+/g //切割字符串为一个个å°å—,以空格或豆å·åˆ†å¼€å®ƒä»¬ï¼Œç»“åˆreplace实现字符串的forEach + var rcomplexType = /^(?:object|array)$/ + var rsvg = /^\[object SVG\w*Element\]$/ + var rwindow = /^\[object (?:Window|DOMWindow|global)\]$/ + var oproto = Object.prototype + var ohasOwn = oproto.hasOwnProperty + var serialize = oproto.toString + var ap = Array.prototype + var aslice = ap.slice + var Registry = {} //将函数æ›å…‰åˆ°æ­¤å¯¹è±¡ä¸Šï¼Œæ–¹ä¾¿è®¿é—®å™¨æ”¶é›†ä¾èµ– + var W3C = window.dispatchEvent + var root = DOC.documentElement + var hyperspace = DOC.createDocumentFragment() + var cinerator = DOC.createElement("div") + var class2type = {} + "Boolean Number String Function Array Date RegExp Object Error".replace(rword, function (name) { + class2type["[object " + name + "]"] = name.toLowerCase() + }) + + + function noop() { + } + + + function oneObject(array, val) { + if (typeof array === "string") { + array = array.match(rword) || [] + } + var result = {}, + value = val !== void 0 ? val : 1 + for (var i = 0, n = array.length; i < n; i++) { + result[array[i]] = value + } + return result + } + +//生æˆUUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript + var generateID = function (prefix) { + prefix = prefix || "avalon" + return String(Math.random() + Math.random()).replace(/\d\.\d{4}/, prefix) + } + + function IE() { + if (window.VBArray) { + var mode = document.documentMode + return mode ? mode : window.XMLHttpRequest ? 7 : 6 + } else { + return 0 + } + } + + var IEVersion = IE() + + avalon = function (el) { //创建jQueryå¼çš„æ— new 实例化结构 + return new avalon.init(el) + } + + /*视æµè§ˆå™¨æƒ…况采用最快的异步回调*/ + avalon.nextTick = new function () {// jshint ignore:line + var tickImmediate = window.setImmediate + var tickObserver = window.MutationObserver + var tickPost = W3C && window.postMessage + if (tickImmediate) { + return tickImmediate.bind(window) + } + + var queue = [] + + function callback() { + var n = queue.length + for (var i = 0; i < n; i++) { + queue[i]() + } + queue = queue.slice(n) + } + + if (tickObserver) { + var node = document.createTextNode("avalon") + new tickObserver(callback).observe(node, {characterData: true})// jshint ignore:line + return function (fn) { + queue.push(fn) + node.data = Math.random() + } + } + + if (tickPost) { + window.addEventListener("message", function (e) { + var source = e.source + if ((source === window || source === null) && e.data === "process-tick") { + e.stopPropagation() + callback() + } + }) + + return function (fn) { + queue.push(fn) + window.postMessage('process-tick', '*') + } + } + + return function (fn) { + setTimeout(fn, 0) + } + }// jshint ignore:line + /********************************************************************* + * avalonçš„é™æ€æ–¹æ³•å®šä¹‰åŒº * + **********************************************************************/ + avalon.init = function (el) { + this[0] = this.element = el + } + avalon.fn = avalon.prototype = avalon.init.prototype + + avalon.type = function (obj) { //å–得目标的类型 + if (obj == null) { + return String(obj) + } + // 早期的webkit内核æµè§ˆå™¨å®žçŽ°äº†å·²åºŸå¼ƒçš„ecma262v4标准,å¯ä»¥å°†æ­£åˆ™å­—é¢é‡å½“作函数使用,因此typeof在判定正则时会返回function + return typeof obj === "object" || typeof obj === "function" ? + class2type[serialize.call(obj)] || "object" : + typeof obj + } + + var isFunction = function (fn) { + return serialize.call(fn) === "[object Function]" + } + + avalon.isFunction = isFunction + + avalon.isWindow = function (obj) { + return rwindow.test(serialize.call(obj)) + } + + /*判定是å¦æ˜¯ä¸€ä¸ªæœ´ç´ çš„javascript对象(Object),ä¸æ˜¯DOM对象,ä¸æ˜¯BOM对象,ä¸æ˜¯è‡ªå®šä¹‰ç±»çš„实例*/ + + avalon.isPlainObject = function (obj) { + // 简å•çš„ typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通ä¸è¿‡ + return serialize.call(obj) === "[object Object]" && Object.getPrototypeOf(obj) === oproto + } + +//与jQuery.extend方法,å¯ç”¨äºŽæµ…æ‹·è´ï¼Œæ·±æ‹·è´ + avalon.mix = avalon.fn.mix = function () { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false + + // 如果第一个å‚数为布尔,判定是å¦æ·±æ‹·è´ + if (typeof target === "boolean") { + deep = target + target = arguments[1] || {} + i++ + } + + //ç¡®ä¿æŽ¥å—方为一个å¤æ‚çš„æ•°æ®ç±»åž‹ + if (typeof target !== "object" && !isFunction(target)) { + target = {} + } + + //如果åªæœ‰ä¸€ä¸ªå‚数,那么新æˆå‘˜æ·»åŠ äºŽmix所在的对象上 + if (i === length) { + target = this + i-- + } + + for (; i < length; i++) { + //åªå¤„ç†éžç©ºå‚æ•° + if ((options = arguments[i]) != null) { + for (name in options) { + src = target[name] + copy = options[name] + // 防止环引用 + if (target === copy) { + continue + } + if (deep && copy && (avalon.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { + + if (copyIsArray) { + copyIsArray = false + clone = src && Array.isArray(src) ? src : [] + + } else { + clone = src && avalon.isPlainObject(src) ? src : {} + } + + target[name] = avalon.mix(deep, clone, copy) + } else if (copy !== void 0) { + target[name] = copy + } + } + } + } + return target + } + + function _number(a, len) { //用于模拟slice, splice的效果 + a = Math.floor(a) || 0 + return a < 0 ? Math.max(len + a, 0) : Math.min(a, len); + } + + avalon.mix({ + rword: rword, + subscribers: subscribers, + version: 1.43, + ui: {}, + log: log, + slice: function (nodes, start, end) { + return aslice.call(nodes, start, end) + }, + noop: noop, + /*如果ä¸ç”¨Error对象å°è£…一下,str在控制å°ä¸‹å¯èƒ½ä¼šä¹±ç */ + error: function (str, e) { + throw new (e || Error)(str)// jshint ignore:line + }, + /*将一个以空格或逗å·éš”开的字符串或数组,转æ¢æˆä¸€ä¸ªé”®å€¼éƒ½ä¸º1的对象*/ + oneObject: oneObject, + /* avalon.range(10) + => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + avalon.range(1, 11) + => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + avalon.range(0, 30, 5) + => [0, 5, 10, 15, 20, 25] + avalon.range(0, -10, -1) + => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] + avalon.range(0) + => []*/ + range: function (start, end, step) { // 用于生æˆæ•´æ•°æ•°ç»„ + step || (step = 1) + if (end == null) { + end = start || 0 + start = 0 + } + var index = -1, + length = Math.max(0, Math.ceil((end - start) / step)), + result = new Array(length) + while (++index < length) { + result[index] = start + start += step + } + return result + }, + eventHooks: {}, + /*绑定事件*/ + bind: function (el, type, fn, phase) { + var hooks = avalon.eventHooks + var hook = hooks[type] + if (typeof hook === "object") { + type = hook.type + if (hook.deel) { + fn = hook.deel(el, type, fn, phase) + } + } + if (!fn.unbind) + el.addEventListener(type, fn, !!phase) + return fn + }, + /*å¸è½½äº‹ä»¶*/ + unbind: function (el, type, fn, phase) { + var hooks = avalon.eventHooks + var hook = hooks[type] + var callback = fn || noop + if (typeof hook === "object") { + type = hook.type + if (hook.deel) { + fn = hook.deel(el, type, fn, false) + } + } + el.removeEventListener(type, callback, !!phase) + }, + /*读写删除元素节点的样å¼*/ + css: function (node, name, value) { + if (node instanceof avalon) { + node = node[0] + } + var prop = /[_-]/.test(name) ? camelize(name) : name, fn + name = avalon.cssName(prop) || prop + if (value === void 0 || typeof value === "boolean") { //获å–æ ·å¼ + fn = cssHooks[prop + ":get"] || cssHooks["@:get"] + if (name === "background") { + name = "backgroundColor" + } + var val = fn(node, name) + return value === true ? parseFloat(val) || 0 : val + } else if (value === "") { //è¯·é™¤æ ·å¼ + node.style[name] = "" + } else { //è®¾ç½®æ ·å¼ + if (value == null || value !== value) { + return + } + if (isFinite(value) && !avalon.cssNumber[prop]) { + value += "px" + } + fn = cssHooks[prop + ":set"] || cssHooks["@:set"] + fn(node, name, value) + } + }, + /*é历数组与对象,回调的第一个å‚数为索引或键å,第二个或元素或键值*/ + each: function (obj, fn) { + if (obj) { //排除null, undefined + var i = 0 + if (isArrayLike(obj)) { + for (var n = obj.length; i < n; i++) { + if (fn(i, obj[i]) === false) + break + } + } else { + for (i in obj) { + if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) { + break + } + } + } + } + }, + //收集元素的data-{{prefix}}-*属性,并转æ¢ä¸ºå¯¹è±¡ + getWidgetData: function (elem, prefix) { + var raw = avalon(elem).data() + var result = {} + for (var i in raw) { + if (i.indexOf(prefix) === 0) { + result[i.replace(prefix, "").replace(/\w/, function (a) { + return a.toLowerCase() + })] = raw[i] + } + } + return result + }, + Array: { + /*åªæœ‰å½“å‰æ•°ç»„ä¸å­˜åœ¨æ­¤å…ƒç´ æ—¶åªæ·»åŠ å®ƒ*/ + ensure: function (target, item) { + if (target.indexOf(item) === -1) { + return target.push(item) + } + }, + /*移除数组中指定ä½ç½®çš„元素,返回布尔表示æˆåŠŸä¸Žå¦*/ + removeAt: function (target, index) { + return !!target.splice(index, 1).length + }, + /*移除数组中第一个匹é…ä¼ å‚的那个元素,返回布尔表示æˆåŠŸä¸Žå¦*/ + remove: function (target, item) { + var index = target.indexOf(item) + if (~index) + return avalon.Array.removeAt(target, index) + return false + } + } + }) + + var bindingHandlers = avalon.bindingHandlers = {} + var bindingExecutors = avalon.bindingExecutors = {} + + /*判定是å¦ç±»æ•°ç»„,如节点集åˆï¼Œçº¯æ•°ç»„,arguments与拥有éžè´Ÿæ•´æ•°çš„length属性的纯JS对象*/ + function isArrayLike(obj) { + if (obj && typeof obj === "object") { + var n = obj.length, + str = serialize.call(obj) + if (/(Array|List|Collection|Map|Arguments)\]$/.test(str)) { + return true + } else if (str === "[object Object]" && n === (n >>> 0)) { + return true //由于ecma262v5能修改对象属性的enumerable,因此ä¸èƒ½ç”¨propertyIsEnumerableæ¥åˆ¤å®šäº† + } + } + return false + } + + +// https://github.com/rsms/js-lru + var Cache = new function () {// jshint ignore:line + function LRU(maxLength) { + this.size = 0 + this.limit = maxLength + this.head = this.tail = void 0 + this._keymap = {} + } + + var p = LRU.prototype + + p.put = function (key, value) { + var entry = { + key: key, + value: value + } + this._keymap[key] = entry + if (this.tail) { + this.tail.newer = entry + entry.older = this.tail + } else { + this.head = entry + } + this.tail = entry + if (this.size === this.limit) { + this.shift() + } else { + this.size++ + } + return value + } + + p.shift = function () { + var entry = this.head + if (entry) { + this.head = this.head.newer + this.head.older = + entry.newer = + entry.older = + this._keymap[entry.key] = void 0 + } + } + p.get = function (key) { + var entry = this._keymap[key] + if (entry === void 0) + return + if (entry === this.tail) { + return entry.value + } + // HEAD--------------TAIL + // <.older .newer> + // <--- add direction -- + // A B C E + if (entry.newer) { + if (entry === this.head) { + this.head = entry.newer + } + entry.newer.older = entry.older // C <-- E. + } + if (entry.older) { + entry.older.newer = entry.newer // C. --> E + } + entry.newer = void 0 // D --x + entry.older = this.tail // D. --> E + if (this.tail) { + this.tail.newer = entry // E. <-- D + } + this.tail = entry + return entry.value + } + return LRU + }// jshint ignore:line + + /********************************************************************* + * DOM åº•å±‚è¡¥ä¸ * + **********************************************************************/ +//safari5+是把contains方法放在Element.prototype上而ä¸æ˜¯Node.prototype + if (!DOC.contains) { + Node.prototype.contains = function (arg) { + return !!(this.compareDocumentPosition(arg) & 16) + } + } + avalon.contains = function (root, el) { + try { + while ((el = el.parentNode)) + if (el === root) + return true + return false + } catch (e) { + return false + } + } + + if (window.SVGElement) { + var svgns = "http://www.w3.org/2000/svg" + var svg = DOC.createElementNS(svgns, "svg") + svg.innerHTML = '' + if (!rsvg.test(svg.firstChild)) {// #409 + /* jshint ignore:start */ + function enumerateNode(node, targetNode) { + if (node && node.childNodes) { + var nodes = node.childNodes + for (var i = 0, el; el = nodes[i++];) { + if (el.tagName) { + var svg = DOC.createElementNS(svgns, + el.tagName.toLowerCase()) + // copy attrs + ap.forEach.call(el.attributes, function (attr) { + svg.setAttribute(attr.name, attr.value) + }) + // 递归处ç†å­èŠ‚点 + enumerateNode(el, svg) + targetNode.appendChild(svg) + } + } + } + } + + /* jshint ignore:end */ + Object.defineProperties(SVGElement.prototype, { + "outerHTML": {//IE9-11,firefoxä¸æ”¯æŒSVG元素的innerHTML,outerHTML属性 + enumerable: true, + configurable: true, + get: function () { + return new XMLSerializer().serializeToString(this) + }, + set: function (html) { + var tagName = this.tagName.toLowerCase(), + par = this.parentNode, + frag = avalon.parseHTML(html) + // æ“作的svg,直接æ’å…¥ + if (tagName === "svg") { + par.insertBefore(frag, this) + // svg节点的å­èŠ‚点类似 + } else { + var newFrag = DOC.createDocumentFragment() + enumerateNode(frag, newFrag) + par.insertBefore(newFrag, this) + } + par.removeChild(this) + } + }, + "innerHTML": { + enumerable: true, + configurable: true, + get: function () { + var s = this.outerHTML + var ropen = new RegExp("<" + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', "i") + var rclose = new RegExp("<\/" + this.nodeName + ">$", "i") + return s.replace(ropen, "").replace(rclose, "") + }, + set: function (html) { + if (avalon.clearHTML) { + avalon.clearHTML(this) + var frag = avalon.parseHTML(html) + enumerateNode(frag, this) + } + } + } + }) + } + } +//========================= event binding ==================== + var eventHooks = avalon.eventHooks +//针对firefox, chrome修正mouseenter, mouseleave(chrome30+) + if (!("onmouseenter" in root)) { + avalon.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" + }, function (origType, fixType) { + eventHooks[origType] = { + type: fixType, + deel: function (elem, _, fn) { + return function (e) { + var t = e.relatedTarget + if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) { + delete e.type + e.type = origType + return fn.call(elem, e) + } + } + } + } + }) + } +//针对IE9+, w3c修正animationend + avalon.each({ + AnimationEvent: "animationend", + WebKitAnimationEvent: "webkitAnimationEnd" + }, function (construct, fixType) { + if (window[construct] && !eventHooks.animationend) { + eventHooks.animationend = { + type: fixType + } + } + }) + + if (DOC.onmousewheel === void 0) { + /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120 + firefox DOMMouseScroll detail 下3 上-3 + firefox wheel detlaY 下3 上-3 + IE9-11 wheel deltaY 下40 上-40 + chrome wheel deltaY 下100 上-100 */ + eventHooks.mousewheel = { + type: "wheel", + deel: function (elem, _, fn) { + return function (e) { + e.wheelDeltaY = e.wheelDelta = e.deltaY > 0 ? -120 : 120 + e.wheelDeltaX = 0 + Object.defineProperty(e, "type", { + value: "mousewheel" + }) + fn.call(elem, e) + } + } + } + } + + /********************************************************************* + * é…置系统 * + **********************************************************************/ + + function kernel(settings) { + for (var p in settings) { + if (!ohasOwn.call(settings, p)) + continue + var val = settings[p] + if (typeof kernel.plugins[p] === "function") { + kernel.plugins[p](val) + } else if (typeof kernel[p] === "object") { + avalon.mix(kernel[p], val) + } else { + kernel[p] = val + } + } + return this + } + + var openTag, closeTag, rexpr, rexprg, rbind, rregexp = /[-.*+?^${}()|[\]\/\\]/g + + function escapeRegExp(target) { + //http://stevenlevithan.com/regex/xregexp/ + //将字符串安全格å¼åŒ–为正则表达å¼çš„æºç  + return (target + "").replace(rregexp, "\\$&") + } + + var plugins = { + loader: function (builtin) { + var flag = innerRequire && builtin + window.require = flag ? innerRequire : otherRequire + window.define = flag ? innerRequire.define : otherDefine + }, + interpolate: function (array) { + openTag = array[0] + closeTag = array[1] + if (openTag === closeTag) { + throw new SyntaxError("openTag!==closeTag") + } else if (array + "" === "") { + kernel.commentInterpolate = true + } else { + var test = openTag + "test" + closeTag + cinerator.innerHTML = test + if (cinerator.innerHTML !== test && cinerator.innerHTML.indexOf("<") > -1) { + throw new SyntaxError("此定界符ä¸åˆæ³•") + } + cinerator.innerHTML = "" + } + var o = escapeRegExp(openTag), + c = escapeRegExp(closeTag) + rexpr = new RegExp(o + "(.*?)" + c) + rexprg = new RegExp(o + "(.*?)" + c, "g") + rbind = new RegExp(o + ".*?" + c + "|\\sms-") + } + } + + kernel.debug = true + kernel.plugins = plugins + kernel.plugins['interpolate'](["{{", "}}"]) + kernel.paths = {} + kernel.shim = {} + kernel.maxRepeatSize = 100 + avalon.config = kernel + var ravalon = /(\w+)\[(avalonctrl)="(\S+)"\]/ + var findNodes = function (str) { + return DOC.querySelectorAll(str) + } + /********************************************************************* + * 事件总线 * + **********************************************************************/ + var EventBus = { + $watch: function (type, callback) { + if (typeof callback === "function") { + var callbacks = this.$events[type] + if (callbacks) { + callbacks.push(callback) + } else { + this.$events[type] = [callback] + } + } else { //é‡æ–°å¼€å§‹ç›‘å¬æ­¤VM的第一é‡ç®€å•å±žæ€§çš„å˜åŠ¨ + this.$events = this.$watch.backup + } + return this + }, + $unwatch: function (type, callback) { + var n = arguments.length + if (n === 0) { //让此VM的所有$watch回调无效化 + this.$watch.backup = this.$events + this.$events = {} + } else if (n === 1) { + this.$events[type] = [] + } else { + var callbacks = this.$events[type] || [] + var i = callbacks.length + while (~--i < 0) { + if (callbacks[i] === callback) { + return callbacks.splice(i, 1) + } + } + } + return this + }, + $fire: function (type) { + var special, i, v, callback + if (/^(\w+)!(\S+)$/.test(type)) { + special = RegExp.$1 + type = RegExp.$2 + } + var events = this.$events + if (!events) + return + var args = aslice.call(arguments, 1) + var detail = [type].concat(args) + if (special === "all") { + for (i in avalon.vmodels) { + v = avalon.vmodels[i] + if (v !== this) { + v.$fire.apply(v, detail) + } + } + } else if (special === "up" || special === "down") { + var elements = events.expr ? findNodes(events.expr) : [] + if (elements.length === 0) + return + for (i in avalon.vmodels) { + v = avalon.vmodels[i] + if (v !== this) { + if (v.$events.expr) { + var eventNodes = findNodes(v.$events.expr) + if (eventNodes.length === 0) { + continue + } + //循环两个vmodel中的节点,查找匹é…(å‘上匹é…或者å‘下匹é…)的节点并设置标识 + /* jshint ignore:start */ + Array.prototype.forEach.call(eventNodes, function (node) { + Array.prototype.forEach.call(elements, function (element) { + var ok = special === "down" ? element.contains(node) : //å‘下æ•èŽ· + node.contains(element) //å‘上冒泡 + if (ok) { + node._avalon = v //符åˆæ¡ä»¶çš„加一个标识 + } + }); + }) + /* jshint ignore:end */ + } + } + } + var nodes = DOC.getElementsByTagName("*") //å®žçŽ°èŠ‚ç‚¹æŽ’åº + var alls = [] + Array.prototype.forEach.call(nodes, function (el) { + if (el._avalon) { + alls.push(el._avalon) + el._avalon = "" + el.removeAttribute("_avalon") + } + }) + if (special === "up") { + alls.reverse() + } + for (i = 0; callback = alls[i++];) { + if (callback.$fire.apply(callback, detail) === false) { + break + } + } + } else { + var callbacks = events[type] || [] + var all = events.$all || [] + for (i = 0; callback = callbacks[i++];) { + if (isFunction(callback)) + callback.apply(this, args) + } + for (i = 0; callback = all[i++];) { + if (isFunction(callback)) + callback.apply(this, arguments) + } + } + } + } + + /********************************************************************* + * modelFactory * + **********************************************************************/ +//avalon最核心的方法的两个方法之一(å¦ä¸€ä¸ªæ˜¯avalon.scan),返回一个ViewModel(VM) + var VMODELS = avalon.vmodels = createMap() //所有vmodel都储存在这里 + avalon.define = function (id, factory) { + var $id = id.$id || id + if (!$id) { + log("warning: vm必须指定$id") + } + if (VMODELS[$id]) { + log("warning: " + $id + " å·²ç»å­˜åœ¨äºŽavalon.vmodels中") + } + if (typeof id === "object") { + var model = modelFactory(id) + } else { + var scope = { + $watch: noop + } + factory(scope) //得到所有定义 + model = modelFactory(scope) //å·å¤©æ¢æ—¥ï¼Œå°†scopeæ¢ä¸ºmodel + stopRepeatAssign = true + factory(model) + stopRepeatAssign = false + } + model.$id = $id + return VMODELS[$id] = model + } + +//一些ä¸éœ€è¦è¢«ç›‘å¬çš„属性 + var $$skipArray = String("$id,$watch,$unwatch,$fire,$events,$model,$skipArray").match(rword) + + function isObservable(name, value, $skipArray) { + if (isFunction(value) || value && value.nodeType) { + return false + } + if ($skipArray.indexOf(name) !== -1) { + return false + } + if ($$skipArray.indexOf(name) !== -1) { + return false + } + var $special = $skipArray.$special + if (name && name.charAt(0) === "$" && !$special[name]) { + return false + } + return true + } + +//ms-with,ms-each, ms-repeat绑定生æˆçš„代ç†å¯¹è±¡å‚¨å­˜æ±  + var midway = createMap() + + function getNewValue(accessor, name, value, $vmodel) { + switch (accessor.type) { + case 0://计算属性 + var getter = accessor.get + var setter = accessor.set + if (isFunction(setter)) { + var $events = $vmodel.$events + var lock = $events[name] + $events[name] = [] //清空回调,防止内部冒泡而触å‘多次$fire + setter.call($vmodel, value) + $events[name] = lock + } + return getter.call($vmodel) //åŒæ­¥$model + case 1://监控属性 + return value + case 2://对象属性(包括数组与哈希) + if (value !== $vmodel.$model[name]) { + var svmodel = accessor.svmodel = objectFactory($vmodel, name, value, accessor.valueType) + value = svmodel.$model //åŒæ­¥$model + var fn = midway[svmodel.$id] + fn && fn() //åŒæ­¥è§†å›¾ + } + return value + } + } + + function modelFactory(source, $special, $model) { + if (Array.isArray(source)) { + var arr = source.concat() + source.length = 0 + var collection = Collection(source)// jshint ignore:line + collection.pushArray(arr) + return collection + } + //0 null undefined || Node || VModel + if (!source || source.nodeType > 0 || (source.$id && source.$events)) { + return source + } + if (!Array.isArray(source.$skipArray)) { + source.$skipArray = [] + } + source.$skipArray.$special = $special || createMap() //强制è¦ç›‘å¬çš„属性 + var $vmodel = {} //è¦è¿”回的对象, 它在IE6-8下å¯èƒ½è¢«å·é¾™è½¬å‡¤ + $model = $model || {} //vmodels.$model属性 + var $events = createMap() //vmodel.$events属性 + var watchedProperties = createMap() //监控属性 + var initCallbacks = [] //åˆå§‹åŒ–æ‰æ‰§è¡Œçš„函数 + for (var i in source) { + (function (name, val) { + $model[name] = val + if (!isObservable(name, val, source.$skipArray)) { + return //过滤所有éžç›‘控属性 + } + //总共产生三ç§accessor + $events[name] = [] + var valueType = avalon.type(val) + var accessor = function (newValue) { + var name = accessor._name + var $vmodel = this + var $model = $vmodel.$model + var oldValue = $model[name] + var $events = $vmodel.$events + + if (arguments.length) { + if (stopRepeatAssign) { + return + } + //计算属性与对象属性需è¦é‡æ–°è®¡ç®—newValue + if (accessor.type !== 1) { + newValue = getNewValue(accessor, name, newValue, $vmodel) + if (!accessor.type) + return + } + if (!isEqual(oldValue, newValue)) { + $model[name] = newValue + notifySubscribers($events[name]) //åŒæ­¥è§†å›¾ + safeFire($vmodel, name, newValue, oldValue) //触å‘$watch回调 + } + } else { + if (accessor.type === 0) { //type 0 计算属性 1 监控属性 2 对象属性 + //计算属性ä¸éœ€è¦æ”¶é›†è§†å›¾åˆ·æ–°å‡½æ•°,都是由其他监控属性代劳 + newValue = accessor.get.call($vmodel) + if (oldValue !== newValue) { + $model[name] = newValue + //这里ä¸ç”¨åŒæ­¥è§†å›¾ + safeFire($vmodel, name, newValue, oldValue) //触å‘$watch回调 + } + return newValue + } else { + collectSubscribers($events[name]) //收集视图函数 + return accessor.svmodel || oldValue + } + } + } + //总共产生三ç§accessor + if (valueType === "object" && isFunction(val.get) && Object.keys(val).length <= 2) { + //第1ç§ä¸ºè®¡ç®—属性, å› å˜é‡ï¼Œé€šè¿‡å…¶ä»–监控属性触å‘å…¶æ”¹å˜ + accessor.set = val.set + accessor.get = val.get + accessor.type = 0 + initCallbacks.push(function () { + var data = { + evaluator: function () { + data.type = Math.random(), + data.element = null + $model[name] = accessor.get.call($vmodel) + }, + element: head, + type: Math.random(), + handler: noop, + args: [] + } + Registry[expose] = data + accessor.call($vmodel) + delete Registry[expose] + }) + } else if (rcomplexType.test(valueType)) { + //第2ç§ä¸ºå¯¹è±¡å±žæ€§ï¼Œäº§ç”Ÿå­VM与监控数组 + accessor.type = 2 + accessor.valueType = valueType + initCallbacks.push(function () { + var svmodel = modelFactory(val, 0, $model[name]) + accessor.svmodel = svmodel + svmodel.$events[subscribers] = $events[name] + }) + } else { + accessor.type = 1 + //第3ç§ä¸ºç›‘控属性,对应简å•çš„æ•°æ®ç±»åž‹ï¼Œè‡ªå˜é‡ + } + accessor._name = name + watchedProperties[name] = accessor + })(i, source[i])// jshint ignore:line + } + + $$skipArray.forEach(function (name) { + delete source[name] + delete $model[name] //这些特殊属性ä¸åº”该在$model中出现 + }) + + $vmodel = Object.defineProperties($vmodel, descriptorFactory(watchedProperties), source) //生æˆä¸€ä¸ªç©ºçš„ViewModel + for (var name in source) { + if (!watchedProperties[name]) { + $vmodel[name] = source[name] + } + } + //添加$id, $model, $events, $watch, $unwatch, $fire + $vmodel.$id = generateID() + $vmodel.$model = $model + $vmodel.$events = $events + for (i in EventBus) { + $vmodel[i] = EventBus[i] + } + + Object.defineProperty($vmodel, "hasOwnProperty", { + value: function (name) { + return name in this.$model + }, + writable: false, + enumerable: false, + configurable: true + }) + + initCallbacks.forEach(function (cb) { //收集ä¾èµ– + cb() + }) + return $vmodel + } + +//比较两个值是å¦ç›¸ç­‰ + var isEqual = Object.is || function (v1, v2) { + if (v1 === 0 && v2 === 0) { + return 1 / v1 === 1 / v2 + } else if (v1 !== v1) { + return v2 !== v2 + } else { + return v1 === v2 + } + } + + function safeFire(a, b, c, d) { + if (a.$events) { + EventBus.$fire.call(a, b, c, d) + } + } + + var descriptorFactory = function (obj) { + var descriptors = createMap() + for (var i in obj) { + descriptors[i] = { + get: obj[i], + set: obj[i], + enumerable: true, + configurable: true + } + } + return descriptors + } + +//应用于第2ç§accessor + function objectFactory(parent, name, value, valueType) { + //a为原æ¥çš„VM, b为新数组或新对象 + var son = parent[name] + if (valueType === "array") { + if (!Array.isArray(value) || son === value) { + return son //fix https://github.com/RubyLouvre/avalon/issues/261 + } + son._.$unwatch() + son.clear() + son._.$watch() + son.pushArray(value.concat()) + return son + } else { + var iterators = parent.$events[name] + var ret = modelFactory(value) + ret.$events[subscribers] = iterators + midway[ret.$id] = function (data) { + while (data = iterators.shift()) { + (function (el) { + avalon.nextTick(function () { + var type = el.type + if (type && bindingHandlers[type]) { //#753 + el.rollback && el.rollback() //还原 ms-with ms-on + bindingHandlers[type](el, el.vmodels) + } + }) + })(data)// jshint ignore:line + } + delete midway[ret.$id] + } + return ret + } + } + + /********************************************************************* + * 监控数组(与ms-each, ms-repeaté…åˆä½¿ç”¨ï¼‰ * + **********************************************************************/ + + function Collection(model) { + var array = [] + array.$id = generateID() + array.$model = model //æ•°æ®æ¨¡åž‹ + array.$events = {} + array.$events[subscribers] = [] + array._ = modelFactory({ + length: model.length + }) + array._.$watch("length", function (a, b) { + array.$fire("length", a, b) + }) + for (var i in EventBus) { + array[i] = EventBus[i] + } + array.$map = { + el: 1 + } + array.$proxy = [] + avalon.mix(array, CollectionPrototype) + return array + } + + function mutateArray(method, pos, n, index, method2, pos2, n2) { + var oldLen = this.length, loop = 2 + while (--loop) { + switch (method) { + case "add": + /* jshint ignore:start */ + var m = pos + n + var array = this.$model.slice(pos, m).map(function (el) { + if (rcomplexType.test(avalon.type(el))) {//转æ¢ä¸ºVM + return el.$id ? el : modelFactory(el, 0, el) + } else { + return el + } + }) + /* jshint ignore:end */ + for (var i = pos; i < m; i++) {//生æˆä»£ç†VM + var proxy = eachProxyAgent(i, this) + this.$proxy.splice(i, 0, proxy) + } + _splice.apply(this, [pos, 0].concat(array)) + this._fire("add", pos, n) + break + case "del": + var ret = this._splice(pos, n) + var removed = this.$proxy.splice(pos, n) //回收代ç†VM + recycleProxies(removed, "each") + this._fire("del", pos, n) + break + } + if (method2) { + method = method2 + pos = pos2 + n = n2 + loop = 2 + method2 = 0 + } + } + resetIndex(this.$proxy, index) + if (this.length !== oldLen) { + this._.length = this.length + } + return ret + } + + var _splice = ap.splice + var CollectionPrototype = { + _splice: _splice, + _fire: function (method, a, b) { + notifySubscribers(this.$events[subscribers], method, a, b) + }, + size: function () { //å–得数组长度,这个函数å¯ä»¥åŒæ­¥è§†å›¾ï¼Œlengthä¸èƒ½ + return this._.length + }, + pushArray: function (array) { + var m = array.length, n = this.length + if (m) { + ap.push.apply(this.$model, array) + mutateArray.call(this, "add", n, m, Math.max(0, n - 1)) + } + return m + n + }, + push: function () { + //http://jsperf.com/closure-with-arguments + var array = [] + var i, n = arguments.length + for (i = 0; i < n; i++) { + array[i] = arguments[i] + } + return this.pushArray(array) + }, + unshift: function () { + var m = arguments.length, n = this.length + if (m) { + ap.unshift.apply(this.$model, arguments) + mutateArray.call(this, "add", 0, m, 0) + } + return m + n //IE67çš„unshiftä¸ä¼šè¿”回长度 + }, + shift: function () { + if (this.length) { + var el = this.$model.shift() + mutateArray.call(this, "del", 0, 1, 0) + return el //返回被移除的元素 + } + }, + pop: function () { + var n = this.length + if (n) { + var el = this.$model.pop() + mutateArray.call(this, "del", n - 1, 1, Math.max(0, n - 2)) + return el //返回被移除的元素 + } + }, + splice: function (start) { + var m = arguments.length, args = [], change + var removed = _splice.apply(this.$model, arguments) + if (removed.length) { //如果用户删掉了元素 + args.push("del", start, removed.length, 0) + change = true + } + if (m > 2) { //如果用户添加了元素 + if (change) { + args.splice(3, 1, 0, "add", start, m - 2) + } else { + args.push("add", start, m - 2, 0) + } + change = true + } + if (change) { //返回被移除的元素 + return mutateArray.apply(this, args) + } else { + return [] + } + }, + contains: function (el) { //判定是å¦åŒ…å« + return this.indexOf(el) !== -1 + }, + remove: function (el) { //移除第一个等于给定值的元素 + return this.removeAt(this.indexOf(el)) + }, + removeAt: function (index) { //移除指定索引上的元素 + if (index >= 0) { + this.$model.splice(index, 1) + return mutateArray.call(this, "del", index, 1, 0) + } + return [] + }, + clear: function () { + recycleProxies(this.$proxy, "each") + this.$model.length = this.$proxy.length = this.length = this._.length = 0 //清空数组 + this._fire("clear", 0) + return this + }, + removeAll: function (all) { //移除N个元素 + if (Array.isArray(all)) { + all.forEach(function (el) { + this.remove(el) + }, this) + } else if (typeof all === "function") { + for (var i = this.length - 1; i >= 0; i--) { + var el = this[i] + if (all(el, i)) { + this.removeAt(i) + } + } + } else { + this.clear() + } + }, + ensure: function (el) { + if (!this.contains(el)) { //åªæœ‰ä¸å­˜åœ¨æ‰push + this.push(el) + } + return this + }, + set: function (index, val) { + if (index >= 0) { + var valueType = avalon.type(val) + if (val && val.$model) { + val = val.$model + } + var target = this[index] + if (valueType === "object") { + for (var i in val) { + if (target.hasOwnProperty(i)) { + target[i] = val[i] + } + } + } else if (valueType === "array") { + target.clear().push.apply(target, val) + } else if (target !== val) { + this[index] = val + this.$model[index] = val + var proxy = this.$proxy[index] + if (proxy) { + notifySubscribers(proxy.$events.el) + } + // this._fire("set", index, val) + } + } + return this + } + } +//相当于原æ¥bindingExecutors.repeat çš„index分支 + function resetIndex(array, pos) { + var last = array.length - 1 + for (var el; el = array[pos]; pos++) { + el.$index = pos + el.$first = pos === 0 + el.$last = pos === last + } + } + + function sortByIndex(array, indexes) { + var map = {}; + for (var i = 0, n = indexes.length; i < n; i++) { + map[i] = array[i] // preserve + var j = indexes[i] + if (j in map) { + array[i] = map[j] + delete map[j] + } else { + array[i] = array[j] + } + } + } + + "sort,reverse".replace(rword, function (method) { + CollectionPrototype[method] = function () { + var newArray = this.$model//这是è¦æŽ’åºçš„新数组 + var oldArray = newArray.concat() //ä¿æŒåŽŸæ¥çŠ¶æ€çš„旧数组 + var mask = Math.random() + var indexes = [] + var hasSort + ap[method].apply(newArray, arguments) //æŽ’åº + for (var i = 0, n = oldArray.length; i < n; i++) { + var neo = newArray[i] + var old = oldArray[i] + if (isEqual(neo, old)) { + indexes.push(i) + } else { + var index = oldArray.indexOf(neo) + indexes.push(index)//得到新数组的æ¯ä¸ªå…ƒç´ åœ¨æ—§æ•°ç»„对应的ä½ç½® + oldArray[index] = mask //å±è”½å·²ç»æ‰¾è¿‡çš„元素 + hasSort = true + } + } + if (hasSort) { + sortByIndex(this, indexes) + sortByIndex(this.$proxy, indexes) + this._fire("move", indexes) + resetIndex(this.$proxy, 0) + } + return this + } + }) + + /********************************************************************* + * ä¾èµ–调度系统 * + **********************************************************************/ + var ronduplex = /^(duplex|on)$/ + + avalon.injectBinding = function (data) { + Registry[expose] = data //暴光此函数,方便collectSubscribers收集 + avalon.openComputedCollect = true + var fn = data.evaluator + if (fn) { //如果是求值函数 + try { + var c = ronduplex.test(data.type) ? data : fn.apply(0, data.args) + if (!data.noRefresh) + data.handler(c, data.element, data) + } catch (e) { + //log("warning:exception throwed in [avalon.injectBinding] " + e) + delete data.evaluator + var node = data.element + if (node.nodeType === 3) { + var parent = node.parentNode + if (kernel.commentInterpolate) { + parent.replaceChild(DOC.createComment(data.value), node) + } else { + node.data = openTag + data.value + closeTag + } + } + } + } + avalon.openComputedCollect = false + delete Registry[expose] + } + + function collectSubscribers(list) { //收集ä¾èµ–于这个访问器的订阅者 + var data = Registry[expose] + if (list && data && avalon.Array.ensure(list, data) && data.element) { //åªæœ‰æ•°ç»„ä¸å­˜åœ¨æ­¤å…ƒç´ æ‰push进去 + addSubscribers(data, list) + } + } + + + function addSubscribers(data, list) { + data.$uuid = data.$uuid || generateID() + list.$uuid = list.$uuid || generateID() + var obj = { + data: data, + list: list, + $$uuid: data.$uuid + list.$uuid + } + if (!$$subscribers[obj.$$uuid]) { + $$subscribers[obj.$$uuid] = 1 + $$subscribers.push(obj) + } + } + + function disposeData(data) { + data.element = null + data.rollback && data.rollback() + for (var key in data) { + data[key] = null + } + } + + function isRemove(el) { + try {//IE下,如果文本节点脱离DOM树,访问parentNode会报错 + if (!el.parentNode) { + return true + } + } catch (e) { + return true + } + return el.msRetain ? 0 : (el.nodeType === 1 ? typeof el.sourceIndex === "number" ? + el.sourceIndex === 0 : !root.contains(el) : !avalon.contains(root, el)) + } + + var $$subscribers = avalon.$$subscribers = [] + var beginTime = new Date() + var oldInfo = {} + + function removeSubscribers() { + var i = $$subscribers.length + var n = i + var k = 0 + var obj + var types = [] + var newInfo = {} + var needTest = {} + while (obj = $$subscribers[--i]) { + var data = obj.data + var type = data.type + if (newInfo[type]) { + newInfo[type]++ + } else { + newInfo[type] = 1 + types.push(type) + } + } + var diff = false + types.forEach(function (type) { + if (oldInfo[type] !== newInfo[type]) { + needTest[type] = 1 + diff = true + } + }) + i = n + //avalon.log("需è¦æ£€æµ‹çš„个数 " + i) + if (diff) { + //avalon.log("有需è¦ç§»é™¤çš„元素") + while (obj = $$subscribers[--i]) { + data = obj.data + if (data.element === void 0) + continue + if (needTest[data.type] && isRemove(data.element)) { //如果它没有在DOMæ ‘ + k++ + $$subscribers.splice(i, 1) + delete $$subscribers[obj.$$uuid] + avalon.Array.remove(obj.list, data) + //log("debug: remove " + data.type) + disposeData(data) + obj.data = obj.list = null + } + } + } + oldInfo = newInfo + // avalon.log("å·²ç»ç§»é™¤çš„个数 " + k) + beginTime = new Date() + } + + function notifySubscribers(list) { //通知ä¾èµ–于这个访问器的订阅者更新自身 + if (list && list.length) { + if (new Date() - beginTime > 444 && typeof list[0] === "object") { + removeSubscribers() + } + var args = aslice.call(arguments, 1) + for (var i = list.length, fn; fn = list[--i];) { + var el = fn.element + if (el && el.parentNode) { + if (fn.$repeat) { + fn.handler.apply(fn, args) //处ç†ç›‘控数组的方法 + } else if (fn.type !== "on") { //事件绑定åªèƒ½ç”±ç”¨æˆ·è§¦å‘,ä¸èƒ½ç”±ç¨‹åºè§¦å‘ + var fun = fn.evaluator || noop + fn.handler(fun.apply(0, fn.args || []), el, fn) + } + } + } + } + } + + /************************************************************************ + * HTML处ç†(parseHTML, innerHTML, clearHTML) * + **************************************************************************/ +//parseHTML的辅助å˜é‡ + var tagHooks = new function () {// jshint ignore:line + avalon.mix(this, { + option: DOC.createElement("select"), + thead: DOC.createElement("table"), + td: DOC.createElement("tr"), + area: DOC.createElement("map"), + tr: DOC.createElement("tbody"), + col: DOC.createElement("colgroup"), + legend: DOC.createElement("fieldset"), + _default: DOC.createElement("div"), + "g": DOC.createElementNS("http://www.w3.org/2000/svg", "svg") + }) + this.optgroup = this.option + this.tbody = this.tfoot = this.colgroup = this.caption = this.thead + this.th = this.td + }// jshint ignore:line + + String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function (tag) { + tagHooks[tag] = tagHooks.g //处ç†SVG + }) + var rtagName = /<([\w:]+)/ + var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig + var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"]) + var script = DOC.createElement("script") + var rhtml = /<|&#?\w+;/ + avalon.parseHTML = function (html) { + var fragment = hyperspace.cloneNode(false) + if (typeof html !== "string") { + return fragment + } + if (!rhtml.test(html)) { + fragment.appendChild(DOC.createTextNode(html)) + return fragment + } + html = html.replace(rxhtml, "<$1>").trim() + var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(), + //å–得其标签å + wrapper = tagHooks[tag] || tagHooks._default, + firstChild + wrapper.innerHTML = html + var els = wrapper.getElementsByTagName("script") + if (els.length) { //使用innerHTML生æˆçš„script节点ä¸ä¼šå‘出请求与执行text属性 + for (var i = 0, el; el = els[i++];) { + if (scriptTypes[el.type]) { + var neo = script.cloneNode(false) //FFä¸èƒ½çœç•¥å‚æ•° + ap.forEach.call(el.attributes, function (attr) { + neo.setAttribute(attr.name, attr.value) + })// jshint ignore:line + neo.text = el.text + el.parentNode.replaceChild(neo, el) + } + } + } + + while (firstChild = wrapper.firstChild) { // å°†wrapperä¸Šçš„èŠ‚ç‚¹è½¬ç§»åˆ°æ–‡æ¡£ç¢Žç‰‡ä¸Šï¼ + fragment.appendChild(firstChild) + } + return fragment + } + + avalon.innerHTML = function (node, html) { + var a = this.parseHTML(html) + this.clearHTML(node).appendChild(a) + } + + avalon.clearHTML = function (node) { + node.textContent = "" + while (node.firstChild) { + node.removeChild(node.firstChild) + } + return node + } + + /********************************************************************* + * 扫æ系统 * + **********************************************************************/ + + avalon.scan = function (elem, vmodel) { + elem = elem || root + var vmodels = vmodel ? [].concat(vmodel) : [] + scanTag(elem, vmodels) + } + +//http://www.w3.org/TR/html5/syntax.html#void-elements + var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase()) + + function checkScan(elem, callback, innerHTML) { + var id = setTimeout(function () { + var currHTML = elem.innerHTML + clearTimeout(id) + if (currHTML === innerHTML) { + callback() + } else { + checkScan(elem, callback, currHTML) + } + }) + } + + + function createSignalTower(elem, vmodel) { + var id = elem.getAttribute("avalonctrl") || vmodel.$id + elem.setAttribute("avalonctrl", id) + vmodel.$events.expr = elem.tagName + '[avalonctrl="' + id + '"]' + } + + var getBindingCallback = function (elem, name, vmodels) { + var callback = elem.getAttribute(name) + if (callback) { + for (var i = 0, vm; vm = vmodels[i++];) { + if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") { + return vm[callback] + } + } + } + } + + function executeBindings(bindings, vmodels) { + for (var i = 0, data; data = bindings[i++];) { + data.vmodels = vmodels + bindingHandlers[data.type](data, vmodels) + if (data.evaluator && data.element && data.element.nodeType === 1) { //移除数æ®ç»‘å®šï¼Œé˜²æ­¢è¢«äºŒæ¬¡è§£æž + //chrome使用removeAttributeNode移除ä¸å­˜åœ¨çš„特性节点时会报错 https://github.com/RubyLouvre/avalon/issues/99 + data.element.removeAttribute(data.name) + } + } + bindings.length = 0 + } + +//https://github.com/RubyLouvre/avalon/issues/636 + var mergeTextNodes = IEVersion && window.MutationObserver ? function (elem) { + var node = elem.firstChild, text + while (node) { + var aaa = node.nextSibling + if (node.nodeType === 3) { + if (text) { + text.nodeValue += node.nodeValue + elem.removeChild(node) + } else { + text = node + } + } else { + text = null + } + node = aaa + } + } : 0 + + var rmsAttr = /ms-(\w+)-?(.*)/ + var priorityMap = { + "if": 10, + "repeat": 90, + "data": 100, + "widget": 110, + "each": 1400, + "with": 1500, + "duplex": 2000, + "on": 3000 + } + + var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit") + var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled") + + function bindingSorter(a, b) { + return a.priority - b.priority + } + + function scanAttr(elem, vmodels) { + //防止setAttribute, removeAttributeæ—¶ attributes自动被åŒæ­¥,导致for循环出错 + var attributes = elem.hasAttributes() ? avalon.slice(elem.attributes) : [] + var bindings = [], + msData = createMap(), + match + for (var i = 0, attr; attr = attributes[i++];) { + if (attr.specified) { + if (match = attr.name.match(rmsAttr)) { + //如果是以指定å‰ç¼€å‘½åçš„ + var type = match[1] + var param = match[2] || "" + var value = attr.value + var name = attr.name + msData[name] = value + if (events[type]) { + param = type + type = "on" + } else if (obsoleteAttrs[type]) { + log("warning!请改用ms-attr-" + type + "代替ms-" + type + "ï¼") + if (type === "enabled") {//åƒæŽ‰ms-enabled绑定,用ms-disabled代替 + log("warning!ms-enabled或ms-attr-enabledå·²ç»è¢«åºŸå¼ƒ") + type = "disabled" + value = "!(" + value + ")" + } + param = type + type = "attr" + elem.removeAttribute(name) + name = "ms-attr-" + param + elem.setAttribute(name, value) + match = [name] + msData[name] = value + } + if (typeof bindingHandlers[type] === "function") { + var binding = { + type: type, + param: param, + element: elem, + name: match[0], + value: value, + priority: type in priorityMap ? priorityMap[type] : type.charCodeAt(0) * 10 + (Number(param) || 0) + } + if (type === "html" || type === "text") { + var token = getToken(value) + avalon.mix(binding, token) + binding.filters = binding.filters.replace(rhasHtml, function () { + binding.type = "html" + binding.group = 1 + return "" + })// jshint ignore:line + } + if (name === "ms-if-loop") { + binding.priority += 100 + } + if (vmodels.length) { + bindings.push(binding) + if (type === "widget") { + elem.msData = elem.msData || msData + } + } + } + } + } + } + var control = elem.type + if (control && msData["ms-duplex"]) { + if (msData["ms-attr-checked"] && /radio|checkbox/.test(control)) { + log("warning!" + control + "控件ä¸èƒ½åŒæ—¶å®šä¹‰ms-attr-checked与ms-duplex") + } + if (msData["ms-attr-value"] && /text|password/.test(control)) { + log("warning!" + control + "控件ä¸èƒ½åŒæ—¶å®šä¹‰ms-attr-value与ms-duplex") + } + } + bindings.sort(bindingSorter) + var scanNode = true + for (i = 0; binding = bindings[i]; i++) { + type = binding.type + if (rnoscanAttrBinding.test(type)) { + return executeBindings(bindings.slice(0, i + 1), vmodels) + } else if (scanNode) { + scanNode = !rnoscanNodeBinding.test(type) + } + } + executeBindings(bindings, vmodels) + if (scanNode && !stopScan[elem.tagName] && rbind.test(elem.innerHTML + elem.textContent)) { + mergeTextNodes && mergeTextNodes(elem) + scanNodeList(elem, vmodels) //扫æå­å­™å…ƒç´  + } + } + + var rnoscanAttrBinding = /^if|widget|repeat$/ + var rnoscanNodeBinding = /^each|with|html|include$/ + + function scanNodeList(parent, vmodels) { + var node = parent.firstChild + while (node) { + var nextNode = node.nextSibling + scanNode(node, node.nodeType, vmodels) + node = nextNode + } + } + + function scanNodeArray(nodes, vmodels) { + for (var i = 0, node; node = nodes[i++];) { + scanNode(node, node.nodeType, vmodels) + } + } + + function scanNode(node, nodeType, vmodels) { + if (nodeType === 1) { + scanTag(node, vmodels) //扫æ元素节点 + if (node.msCallback) { + node.msCallback() + node.msCallback = void 0 + } + } else if (nodeType === 3 && rexpr.test(node.data)) { + scanText(node, vmodels) //扫æ文本节点 + } else if (kernel.commentInterpolate && nodeType === 8 && !rexpr.test(node.nodeValue)) { + scanText(node, vmodels) //扫æ注释节点 + } + } + + function scanTag(elem, vmodels, node) { + //扫æé¡ºåº ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100) + //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)åž«åŽ + var a = elem.getAttribute("ms-skip") + var b = elem.getAttributeNode("ms-important") + var c = elem.getAttributeNode("ms-controller") + if (typeof a === "string") { + return + } else if (node = b || c) { + var newVmodel = avalon.vmodels[node.value] + if (!newVmodel) { + return + } + //ms-importantä¸åŒ…å«çˆ¶VM,ms-controller相å + vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels) + elem.removeAttribute(node.name) //removeAttributeNodeä¸ä¼šåˆ·æ–°[ms-controller]æ ·å¼è§„则 + elem.classList.remove(node.name) + createSignalTower(elem, newVmodel) + } + scanAttr(elem, vmodels) //扫æ特性节点 + } + + var rhasHtml = /\|\s*html\s*/, + r11a = /\|\|/g, + rlt = /</g, + rgt = />/g, + rstringLiteral = /(['"])(\\\1|.)+?\1/g + + function getToken(value) { + if (value.indexOf("|") > 0) { + var scapegoat = value.replace(rstringLiteral, function (_) { + return Array(_.length + 1).join("1")// jshint ignore:line + }) + var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或 + if (index > -1) { + return { + filters: value.slice(index), + value: value.slice(0, index), + expr: true + } + } + } + return { + value: value, + filters: "", + expr: true + } + } + + function scanExpr(str) { + var tokens = [], + value, start = 0, + stop + do { + stop = str.indexOf(openTag, start) + if (stop === -1) { + break + } + value = str.slice(start, stop) + if (value) { // {{ 左边的文本 + tokens.push({ + value: value, + filters: "", + expr: false + }) + } + start = stop + openTag.length + stop = str.indexOf(closeTag, start) + if (stop === -1) { + break + } + value = str.slice(start, stop) + if (value) { //处ç†{{ }}æ’å€¼è¡¨è¾¾å¼ + tokens.push(getToken(value)) + } + start = stop + closeTag.length + } while (1) + value = str.slice(start) + if (value) { //}} å³è¾¹çš„文本 + tokens.push({ + value: value, + expr: false, + filters: "" + }) + } + return tokens + } + + function scanText(textNode, vmodels) { + var bindings = [] + if (textNode.nodeType === 8) { + var token = getToken(textNode.nodeValue) + var tokens = [token] + } else { + tokens = scanExpr(textNode.data) + } + if (tokens.length) { + for (var i = 0; token = tokens[i++];) { + var node = DOC.createTextNode(token.value) //将文本转æ¢ä¸ºæ–‡æœ¬èŠ‚点,并替æ¢åŽŸæ¥çš„文本节点 + if (token.expr) { + token.type = "text" + token.element = node + token.filters = token.filters.replace(rhasHtml, function () { + token.type = "html" + token.group = 1 + return "" + })// jshint ignore:line + bindings.push(token) //收集带有æ’值表达å¼çš„文本 + } + hyperspace.appendChild(node) + } + textNode.parentNode.replaceChild(hyperspace, textNode) + if (bindings.length) + executeBindings(bindings, vmodels) + } + } + + /********************************************************************* + * avalon的原型方法定义区 * + **********************************************************************/ + + function hyphen(target) { + //转æ¢ä¸ºè¿žå­—符线风格 + return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase() + } + + function camelize(target) { + //转æ¢ä¸ºé©¼å³°é£Žæ ¼ + if (target.indexOf("-") < 0 && target.indexOf("_") < 0) { + return target //æå‰åˆ¤æ–­ï¼Œæ高getStyle等的效率 + } + return target.replace(/[-_][^-_]/g, function (match) { + return match.charAt(1).toUpperCase() + }) + } + + "add,remove".replace(rword, function (method) { + avalon.fn[method + "Class"] = function (cls) { + var el = this[0] + //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26 + if (cls && typeof cls === "string" && el && el.nodeType === 1) { + cls.replace(/\S+/g, function (c) { + el.classList[method](c) + }) + } + return this + } + }) + + avalon.fn.mix({ + hasClass: function (cls) { + var el = this[0] || {} //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支æŒclassList,chrome24+,firefox26+支æŒclassList2.0 + return el.nodeType === 1 && el.classList.contains(cls) + }, + toggleClass: function (value, stateVal) { + var className, i = 0 + var classNames = String(value).split(/\s+/) + var isBool = typeof stateVal === "boolean" + while ((className = classNames[i++])) { + var state = isBool ? stateVal : !this.hasClass(className) + this[state ? "addClass" : "removeClass"](className) + } + return this + }, + attr: function (name, value) { + if (arguments.length === 2) { + this[0].setAttribute(name, value) + return this + } else { + return this[0].getAttribute(name) + } + }, + data: function (name, value) { + name = "data-" + hyphen(name || "") + switch (arguments.length) { + case 2: + this.attr(name, value) + return this + case 1: + var val = this.attr(name) + return parseData(val) + case 0: + var ret = {} + ap.forEach.call(this[0].attributes, function (attr) { + if (attr) { + name = attr.name + if (!name.indexOf("data-")) { + name = camelize(name.slice(5)) + ret[name] = parseData(attr.value) + } + } + }) + return ret + } + }, + removeData: function (name) { + name = "data-" + hyphen(name) + this[0].removeAttribute(name) + return this + }, + css: function (name, value) { + if (avalon.isPlainObject(name)) { + for (var i in name) { + avalon.css(this, i, name[i]) + } + } else { + var ret = avalon.css(this, name, value) + } + return ret !== void 0 ? ret : this + }, + position: function () { + var offsetParent, offset, + elem = this[0], + parentOffset = { + top: 0, + left: 0 + }; + if (!elem) { + return + } + if (this.css("position") === "fixed") { + offset = elem.getBoundingClientRect() + } else { + offsetParent = this.offsetParent() //得到真正的offsetParent + offset = this.offset() // 得到正确的offsetParent + if (offsetParent[0].tagName !== "HTML") { + parentOffset = offsetParent.offset() + } + parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true) + parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true) + // Subtract offsetParent scroll positions + parentOffset.top -= offsetParent.scrollTop() + parentOffset.left -= offsetParent.scrollLeft() + } + return { + top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true), + left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true) + } + }, + offsetParent: function () { + var offsetParent = this[0].offsetParent + while (offsetParent && avalon.css(offsetParent, "position") === "static") { + offsetParent = offsetParent.offsetParent; + } + return avalon(offsetParent || root) + }, + bind: function (type, fn, phase) { + if (this[0]) { //此方法ä¸ä¼šé“¾ + return avalon.bind(this[0], type, fn, phase) + } + }, + unbind: function (type, fn, phase) { + if (this[0]) { + avalon.unbind(this[0], type, fn, phase) + } + return this + }, + val: function (value) { + var node = this[0] + if (node && node.nodeType === 1) { + var get = arguments.length === 0 + var access = get ? ":get" : ":set" + var fn = valHooks[getValType(node) + access] + if (fn) { + var val = fn(node, value) + } else if (get) { + return (node.value || "").replace(/\r/g, "") + } else { + node.value = value + } + } + return get ? val : this + } + }) + + if (root.dataset) { + avalon.fn.data = function (name, val) { + name = name && camelize(name) + var dataset = this[0].dataset + switch (arguments.length) { + case 2: + dataset[name] = val + return this + case 1: + val = dataset[name] + return parseData(val) + case 0: + var ret = createMap() + for (name in dataset) { + ret[name] = parseData(dataset[name]) + } + return ret + } + } + } + var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/ + avalon.parseJSON = JSON.parse + + function parseData(data) { + try { + if (typeof data === "object") + return data + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? JSON.parse(data) : data + } catch (e) { + } + return data + } + + avalon.each({ + scrollLeft: "pageXOffset", + scrollTop: "pageYOffset" + }, function (method, prop) { + avalon.fn[method] = function (val) { + var node = this[0] || {}, win = getWindow(node), + top = method === "scrollTop" + if (!arguments.length) { + return win ? win[prop] : node[method] + } else { + if (win) { + win.scrollTo(!top ? val : win[prop], top ? val : win[prop]) + } else { + node[method] = val + } + } + } + }) + + function getWindow(node) { + return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView : false + } + +//=============================css相关================================== + var cssHooks = avalon.cssHooks = createMap() + var prefixes = ["", "-webkit-", "-moz-", "-ms-"] //去掉opera-15çš„æ”¯æŒ + var cssMap = { + "float": "cssFloat" + } + avalon.cssNumber = oneObject("columnCount,order,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom") + + avalon.cssName = function (name, host, camelCase) { + if (cssMap[name]) { + return cssMap[name] + } + host = host || root.style + for (var i = 0, n = prefixes.length; i < n; i++) { + camelCase = camelize(prefixes[i] + name) + if (camelCase in host) { + return (cssMap[name] = camelCase) + } + } + return null + } + cssHooks["@:set"] = function (node, name, value) { + node.style[name] = value + } + + cssHooks["@:get"] = function (node, name) { + if (!node || !node.style) { + throw new Error("getComputedStyleè¦æ±‚传入一个节点 " + node) + } + var ret, computed = getComputedStyle(node) + if (computed) { + ret = name === "filter" ? computed.getPropertyValue(name) : computed[name] + if (ret === "") { + ret = node.style[name] //其他æµè§ˆå™¨éœ€è¦æˆ‘们手动å–内è”æ ·å¼ + } + } + return ret + } + cssHooks["opacity:get"] = function (node) { + var ret = cssHooks["@:get"](node, "opacity") + return ret === "" ? "1" : ret + } + + "top,left".replace(rword, function (name) { + cssHooks[name + ":get"] = function (node) { + var computed = cssHooks["@:get"](node, name) + return /px$/.test(computed) ? computed : + avalon(node).position()[name] + "px" + } + }) + var cssShow = { + position: "absolute", + visibility: "hidden", + display: "block" + } + var rdisplayswap = /^(none|table(?!-c[ea]).+)/ + + function showHidden(node, array) { + //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html + if (node.offsetWidth <= 0) { //opera.offsetWidthå¯èƒ½å°äºŽ0 + var styles = getComputedStyle(node, null) + if (rdisplayswap.test(styles["display"])) { + var obj = { + node: node + } + for (var name in cssShow) { + obj[name] = styles[name] + node.style[name] = cssShow[name] + } + array.push(obj) + } + var parent = node.parentNode + if (parent && parent.nodeType === 1) { + showHidden(parent, array) + } + } + } + + "Width,Height".replace(rword, function (name) { //fix 481 + var method = name.toLowerCase(), + clientProp = "client" + name, + scrollProp = "scroll" + name, + offsetProp = "offset" + name + cssHooks[method + ":get"] = function (node, which, override) { + var boxSizing = -4 + if (typeof override === "number") { + boxSizing = override + } + which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"] + var ret = node[offsetProp] // border-box 0 + if (boxSizing === 2) { // margin-box 2 + return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true) + } + if (boxSizing < 0) { // padding-box -2 + ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true) + } + if (boxSizing === -4) { // content-box -4 + ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true) + } + return ret + } + cssHooks[method + "&get"] = function (node) { + var hidden = []; + showHidden(node, hidden); + var val = cssHooks[method + ":get"](node) + for (var i = 0, obj; obj = hidden[i++];) { + node = obj.node + for (var n in obj) { + if (typeof obj[n] === "string") { + node.style[n] = obj[n] + } + } + } + return val; + } + avalon.fn[method] = function (value) { //会忽视其display + var node = this[0] + if (arguments.length === 0) { + if (node.setTimeout) { //å–得窗å£å°ºå¯¸,IE9åŽå¯ä»¥ç”¨node.innerWidth /innerHeight代替 + return node["inner" + name] + } + if (node.nodeType === 9) { //å–得页é¢å°ºå¯¸ + var doc = node.documentElement + //FF chrome html.scrollHeight< body.scrollHeight + //IE æ ‡å‡†æ¨¡å¼ : html.scrollHeight> body.scrollHeight + //IE æ€ªå¼‚æ¨¡å¼ : html.scrollHeight 最大等于å¯è§†çª—å£å¤šä¸€ç‚¹ï¼Ÿ + return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp]) + } + return cssHooks[method + "&get"](node) + } else { + return this.css(method, value) + } + } + avalon.fn["inner" + name] = function () { + return cssHooks[method + ":get"](this[0], void 0, -2) + } + avalon.fn["outer" + name] = function (includeMargin) { + return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0) + } + }) + avalon.fn.offset = function () { //å–å¾—è·ç¦»é¡µé¢å·¦å³è§’çš„åæ ‡ + var node = this[0] + try { + var rect = node.getBoundingClientRect() + // Make sure element is not hidden (display: none) or disconnected + // https://github.com/jquery/jquery/pull/2043/files#r23981494 + if (rect.width || rect.height || node.getClientRects().length) { + var doc = node.ownerDocument + var root = doc.documentElement + var win = doc.defaultView + return { + top: rect.top + win.pageYOffset - root.clientTop, + left: rect.left + win.pageXOffset - root.clientLeft + } + } + } catch (e) { + return { + left: 0, + top: 0 + } + } + } + //=============================val相关======================= + + function getValType(elem) { + var ret = elem.tagName.toLowerCase() + return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret + } + + var valHooks = { + "select:get": function (node, value) { + var option, options = node.options, + index = node.selectedIndex, + one = node.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? max : one ? index : 0 + for (; i < max; i++) { + option = options[i] + //æ—§å¼IE在resetåŽä¸ä¼šæ”¹å˜selected,需è¦æ”¹ç”¨i === index判定 + //我们过滤所有disabledçš„option元素,但在safari5下,如果设置select为disable,那么其所有孩å­éƒ½disable + //因此当一个元素为disable,需è¦æ£€æµ‹å…¶æ˜¯å¦æ˜¾å¼è®¾ç½®äº†disableåŠå…¶çˆ¶èŠ‚点的disable情况 + if ((option.selected || i === index) && !option.disabled) { + value = option.value + if (one) { + return value + } + //收集所有selected值组æˆæ•°ç»„返回 + values.push(value) + } + } + return values + }, + "select:set": function (node, values, optionSet) { + values = [].concat(values) //强制转æ¢ä¸ºæ•°ç»„ + for (var i = 0, el; el = node.options[i++];) { + if ((el.selected = values.indexOf(el.value) > -1)) { + optionSet = true + } + } + if (!optionSet) { + node.selectedIndex = -1 + } + } + } + /********************************************************************* + * 编译系统 * + **********************************************************************/ + var quote = JSON.stringify + + var keywords = [ + "break,case,catch,continue,debugger,default,delete,do,else,false", + "finally,for,function,if,in,instanceof,new,null,return,switch,this", + "throw,true,try,typeof,var,void,while,with", /* 关键字*/ + "abstract,boolean,byte,char,class,const,double,enum,export,extends", + "final,float,goto,implements,import,int,interface,long,native", + "package,private,protected,public,short,static,super,synchronized", + "throws,transient,volatile", /*ä¿ç•™å­—*/ + "arguments,let,yield,undefined" /* ECMA 5 - use strict*/].join(",") + var rrexpstr = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g + var rsplit = /[^\w$]+/g + var rkeywords = new RegExp(["\\b" + keywords.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g') + var rnumber = /\b\d[^,]*/g + var rcomma = /^,+|,+$/g + var cacheVars = new Cache(512) + var getVariables = function (code) { + var key = "," + code.trim() + var ret = cacheVars.get(key) + if (ret) { + return ret + } + var match = code + .replace(rrexpstr, "") + .replace(rsplit, ",") + .replace(rkeywords, "") + .replace(rnumber, "") + .replace(rcomma, "") + .split(/^$|,+/) + return cacheVars.put(key, uniqSet(match)) + } + /*添加赋值语å¥*/ + + function addAssign(vars, scope, name, data) { + var ret = [], + prefix = " = " + name + "." + var isProxy = /\$proxy\$each/.test(scope.$id) + for (var i = vars.length, prop; prop = vars[--i];) { + var el = isProxy && scope.$map[prop] ? "el" : prop + if (scope.hasOwnProperty(el)) { + ret.push(prop + prefix + el) + data.vars.push(prop) + if (data.type === "duplex") { + vars.get = name + "." + el + } + vars.splice(i, 1) + } + } + return ret + } + + function uniqSet(array) { + var ret = [], + unique = {} + for (var i = 0; i < array.length; i++) { + var el = array[i] + var id = el && typeof el.$id === "string" ? el.$id : el + if (!unique[id]) { + unique[id] = ret.push(el) + } + } + return ret + } + +//缓存求值函数,以便多次利用 + var cacheExprs = new Cache(128) +//å–得求值函数åŠå…¶ä¼ å‚ + var rduplex = /\w\[.*\]|\w\.\w/ + var rproxy = /(\$proxy\$[a-z]+)\d+$/ + var rthimRightParentheses = /\)\s*$/ + var rthimOtherParentheses = /\)\s*\|/g + var rquoteFilterName = /\|\s*([$\w]+)/g + var rpatchBracket = /"\s*\["/g + var rthimLeftParentheses = /"\s*\(/g + + function parseFilter(val, filters) { + filters = filters + .replace(rthimRightParentheses, "")//处ç†æœ€åŽçš„å°æ‹¬å· + .replace(rthimOtherParentheses, function () {//处ç†å…¶ä»–å°æ‹¬å· + return "],|" + }) + .replace(rquoteFilterName, function (a, b) { //处ç†|åŠå®ƒåŽé¢çš„过滤器的åå­— + return "[" + quote(b) + }) + .replace(rpatchBracket, function () { + return '"],["' + }) + .replace(rthimLeftParentheses, function () { + return '",' + }) + "]" + return "return avalon.filters.$filter(" + val + ", " + filters + ")" + } + + function parseExpr(code, scopes, data) { + var dataType = data.type + var filters = data.filters || "" + var exprId = scopes.map(function (el) { + return String(el.$id).replace(rproxy, "$1") + }) + code + dataType + filters + var vars = getVariables(code).concat(), + assigns = [], + names = [], + args = [], + prefix = "" + //args 是一个对象数组, names 是将è¦ç”Ÿæˆçš„求值函数的å‚æ•° + scopes = uniqSet(scopes) + data.vars = [] + for (var i = 0, sn = scopes.length; i < sn; i++) { + if (vars.length) { + var name = "vm" + expose + "_" + i + names.push(name) + args.push(scopes[i]) + assigns.push.apply(assigns, addAssign(vars, scopes[i], name, data)) + } + } + if (!assigns.length && dataType === "duplex") { + return + } + if (dataType !== "duplex" && (code.indexOf("||") > -1 || code.indexOf("&&") > -1)) { + //https://github.com/RubyLouvre/avalon/issues/583 + data.vars.forEach(function (v) { + var reg = new RegExp("\\b" + v + "(?:\\.\\w+|\\[\\w+\\])+", "ig") + code = code.replace(reg, function (_) { + var c = _.charAt(v.length) + var r = IEVersion ? code.slice(arguments[1] + _.length) : RegExp.rightContext + var method = /^\s*\(/.test(r) + if (c === "." || c === "[" || method) {//比如v为aa,我们åªåŒ¹é…aa.bb,aa[cc],ä¸åŒ¹é…aaa.xxx + var name = "var" + String(Math.random()).replace(/^0\./, "") + if (method) {//array.size() + var array = _.split(".") + if (array.length > 2) { + var last = array.pop() + assigns.push(name + " = " + array.join(".")) + return name + "." + last + } else { + return _ + } + } + assigns.push(name + " = " + _) + return name + } else { + return _ + } + }) + }) + } + //---------------args---------------- + data.args = args + //---------------cache---------------- + var fn = cacheExprs.get(exprId) //直接从缓存,å…å¾—é‡å¤ç”Ÿæˆ + if (fn) { + data.evaluator = fn + return + } + prefix = assigns.join(", ") + if (prefix) { + prefix = "var " + prefix + } + if (/\S/.test(filters)) { //文本绑定,åŒå·¥ç»‘定æ‰æœ‰è¿‡æ»¤å™¨ + if (!/text|html/.test(data.type)) { + throw Error("ms-" + data.type + "ä¸æ”¯æŒè¿‡æ»¤å™¨") + } + code = "\nvar ret" + expose + " = " + code + ";\r\n" + code += parseFilter("ret" + expose, filters) + } else if (dataType === "duplex") { //åŒå·¥ç»‘定 + var _body = "'use strict';\nreturn function(vvv){\n\t" + + prefix + + ";\n\tif(!arguments.length){\n\t\treturn " + + code + + "\n\t}\n\t" + (!rduplex.test(code) ? vars.get : code) + + "= vvv;\n} " + try { + fn = Function.apply(noop, names.concat(_body)) + data.evaluator = cacheExprs.put(exprId, fn) + } catch (e) { + log("debug: parse error," + e.message) + } + return + } else if (dataType === "on") { //事件绑定 + if (code.indexOf("(") === -1) { + code += ".call(this, $event)" + } else { + code = code.replace("(", ".call(this,") + } + names.push("$event") + code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需è¦Function("return ;") + var lastIndex = code.lastIndexOf("\nreturn") + var header = code.slice(0, lastIndex) + var footer = code.slice(lastIndex) + code = header + "\n" + footer + } else { //其他绑定 + code = "\nreturn " + code + ";" //IE全家 Function("return ")出错,需è¦Function("return ;") + } + try { + fn = Function.apply(noop, names.concat("'use strict';\n" + prefix + code)) + data.evaluator = cacheExprs.put(exprId, fn) + } catch (e) { + log("debug: parse error," + e.message) + } finally { + vars = assigns = names = null //释放内存 + } + } + + +//parseExprçš„æ™ºèƒ½å¼•ç”¨ä»£ç† + + function parseExprProxy(code, scopes, data, tokens, noRegister) { + if (Array.isArray(tokens)) { + code = tokens.map(function (el) { + return el.expr ? "(" + el.value + ")" : quote(el.value) + }).join(" + ") + } + parseExpr(code, scopes, data) + if (data.evaluator && !noRegister) { + data.handler = bindingExecutors[data.handlerName || data.type] + //方便调试 + //这里éžå¸¸é‡è¦,我们通过判定视图刷新函数的element是å¦åœ¨DOM树决定 + //将它移出订阅者列表 + avalon.injectBinding(data) + } + } + + avalon.parseExprProxy = parseExprProxy + var bools = ["autofocus,autoplay,async,allowTransparency,checked,controls", + "declare,disabled,defer,defaultChecked,defaultSelected", + "contentEditable,isMap,loop,multiple,noHref,noResize,noShade", + "open,readOnly,selected" + ].join(",") + var boolMap = {} + bools.replace(rword, function (name) { + boolMap[name.toLowerCase()] = name + }) + + var propMap = { //属性å映射 + "accept-charset": "acceptCharset", + "char": "ch", + "charoff": "chOff", + "class": "className", + "for": "htmlFor", + "http-equiv": "httpEquiv" + } + + var anomaly = ["accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan", + "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight", + "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign" + ].join(",") + anomaly.replace(rword, function (name) { + propMap[name.toLowerCase()] = name + }) + + var rnoscripts = /(?:[\s\S]+?)<\/noscript>/img + var rnoscriptText = /([\s\S]+?)<\/noscript>/im + + var getXHR = function () { + return new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP") // jshint ignore:line + } + + var cacheTmpls = avalon.templateCache = {} + + bindingHandlers.attr = function (data, vmodels) { + var text = data.value.trim(), + simple = true + if (text.indexOf(openTag) > -1 && text.indexOf(closeTag) > 2) { + simple = false + if (rexpr.test(text) && RegExp.rightContext === "" && RegExp.leftContext === "") { + simple = true + text = RegExp.$1 + } + } + if (data.type === "include") { + var elem = data.element + data.includeRendered = getBindingCallback(elem, "data-include-rendered", vmodels) + data.includeLoaded = getBindingCallback(elem, "data-include-loaded", vmodels) + var outer = data.includeReplace = !!avalon(elem).data("includeReplace") + if (avalon(elem).data("includeCache")) { + data.templateCache = {} + } + data.startInclude = DOC.createComment("ms-include") + data.endInclude = DOC.createComment("ms-include-end") + if (outer) { + data.element = data.startInclude + elem.parentNode.insertBefore(data.startInclude, elem) + elem.parentNode.insertBefore(data.endInclude, elem.nextSibling) + } else { + elem.insertBefore(data.startInclude, elem.firstChild) + elem.appendChild(data.endInclude) + } + } + data.handlerName = "attr" //handleName用于处ç†å¤šç§ç»‘定共用åŒä¸€ç§bindingExecutor的情况 + parseExprProxy(text, vmodels, data, (simple ? 0 : scanExpr(data.value))) + } + + bindingExecutors.attr = function (val, elem, data) { + var method = data.type, + attrName = data.param + if (method === "css") { + avalon(elem).css(attrName, val) + } else if (method === "attr") { + // ms-attr-class="xxx" vm.xxx="aaa bbb ccc"将元素的className设置为aaa bbb ccc + // ms-attr-class="xxx" vm.xxx=false 清空元素的所有类å + // ms-attr-name="yyy" vm.yyy="ooo" 为元素设置name属性 + var toRemove = (val === false) || (val === null) || (val === void 0) + + if (!W3C && propMap[attrName]) { //æ—§å¼IE下需è¦è¿›è¡Œå字映射 + attrName = propMap[attrName] + } + var bool = boolMap[attrName] + if (typeof elem[bool] === "boolean") { + elem[bool] = !!val //布尔属性必须使用el.xxx = true|falseæ–¹å¼è®¾å€¼ + if (!val) { //如果为false, IE全系列下相当于setAttribute(xxx,''),会影å“到样å¼,需è¦è¿›ä¸€æ­¥å¤„ç† + toRemove = true + } + } + if (toRemove) { + return elem.removeAttribute(attrName) + } + + //SVGåªèƒ½ä½¿ç”¨setAttribute(xxx, yyy), VMLåªèƒ½ä½¿ç”¨elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy + var isInnate = rsvg.test(elem) ? false : (DOC.namespaces && isVML(elem)) ? true : attrName in elem.cloneNode(false) + if (isInnate) { + elem[attrName] = val + } else { + elem.setAttribute(attrName, val) + } + } else if (method === "include" && val) { + var vmodels = data.vmodels + var rendered = data.includeRendered + var loaded = data.includeLoaded + var replace = data.includeReplace + var target = replace ? elem.parentNode : elem + var scanTemplate = function (text) { + if (loaded) { + var newText = loaded.apply(target, [text].concat(vmodels)) + if (typeof newText === "string") + text = newText + } + if (rendered) { + checkScan(target, function () { + rendered.call(target) + }, NaN) + } + var lastID = data.includeLastID + if (data.templateCache && lastID && lastID !== val) { + var lastTemplate = data.templateCache[lastID] + if (!lastTemplate) { + lastTemplate = data.templateCache[lastID] = DOC.createElement("div") + ifGroup.appendChild(lastTemplate) + } + } + data.includeLastID = val + while (true) { + var node = data.startInclude.nextSibling + if (node && node !== data.endInclude) { + target.removeChild(node) + if (lastTemplate) + lastTemplate.appendChild(node) + } else { + break + } + } + var dom = getTemplateNodes(data, val, text) + var nodes = avalon.slice(dom.childNodes) + target.insertBefore(dom, data.endInclude) + scanNodeArray(nodes, vmodels) + } + + if (data.param === "src") { + if (typeof cacheTmpls[val] === "string") { + avalon.nextTick(function () { + scanTemplate(cacheTmpls[val]) + }) + } else if (Array.isArray(cacheTmpls[val])) { //#805 防止在循环绑定中å‘出许多相åŒçš„请求 + cacheTmpls[val].push(scanTemplate) + } else { + var xhr = getXHR() + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + var s = xhr.status + if (s >= 200 && s < 300 || s === 304 || s === 1223) { + var text = xhr.responseText + for (var f = 0, fn; fn = cacheTmpls[val][f++];) { + fn(text) + } + cacheTmpls[val] = text + } + } + } + cacheTmpls[val] = [scanTemplate] + xhr.open("GET", val, true) + if ("withCredentials" in xhr) { + xhr.withCredentials = true + } + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") + xhr.send(null) + } + } else { + //IE系列与够新的标准æµè§ˆå™¨æ”¯æŒé€šè¿‡IDå–得元素(firefox14+) + //http://tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ + var el = val && val.nodeType === 1 ? val : DOC.getElementById(val) + if (el) { + if (el.tagName === "NOSCRIPT" && !(el.innerHTML || el.fixIE78)) { //IE7-8 innerText,innerHTML都无法å–得其内容,IE6能å–å¾—å…¶innerHTML + xhr = getXHR() //IE9-11与chromeçš„innerHTML会得到转义的内容,它们的innerTextå¯ä»¥ + xhr.open("GET", location, false) //谢谢Nodejs 乱炖群 深圳-纯属虚构 + xhr.send(null) + //http://bbs.csdn.net/topics/390349046?page=1#post-393492653 + var noscripts = DOC.getElementsByTagName("noscript") + var array = (xhr.responseText || "").match(rnoscripts) || [] + var n = array.length + for (var i = 0; i < n; i++) { + var tag = noscripts[i] + if (tag) { //IE6-8中noscript标签的innerHTML,innerText是åªè¯»çš„ + tag.style.display = "none" //http://haslayout.net/css/noscript-Ghost-Bug + tag.fixIE78 = (array[i].match(rnoscriptText) || ["", " "])[1] + } + } + } + avalon.nextTick(function () { + scanTemplate(el.fixIE78 || el.value || el.innerText || el.innerHTML) + }) + } + } + } else { + if (!root.hasAttribute && typeof val === "string" && (method === "src" || method === "href")) { + val = val.replace(/&/g, "&") //处ç†IE67自动转义的问题 + } + elem[method] = val + if (window.chrome && elem.tagName === "EMBED") { + var parent = elem.parentNode //#525 chrome1-37下embed标签动æ€è®¾ç½®srcä¸èƒ½å‘生请求 + var comment = document.createComment("ms-src") + parent.replaceChild(comment, elem) + parent.replaceChild(elem, comment) + } + } + } + + function getTemplateNodes(data, id, text) { + var div = data.templateCache && data.templateCache[id] + if (div) { + var dom = DOC.createDocumentFragment(), + firstChild + while (firstChild = div.firstChild) { + dom.appendChild(firstChild) + } + return dom + } + return avalon.parseHTML(text) + } + +//这几个指令都å¯ä»¥ä½¿ç”¨æ’值表达å¼ï¼Œå¦‚ms-src="aaa/{{b}}/{{c}}.html" + "title,alt,src,value,css,include,href".replace(rword, function (name) { + bindingHandlers[name] = bindingHandlers.attr + }) +//æ ¹æ®VM的属性值或表达å¼çš„值切æ¢ç±»å,ms-class="xxx yyy zzz:flag" +//http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html + bindingHandlers["class"] = function (data, vmodels) { + var oldStyle = data.param, + text = data.value, + rightExpr + data.handlerName = "class" + if (!oldStyle || isFinite(oldStyle)) { + data.param = "" //去掉数字 + var noExpr = text.replace(rexprg, function (a) { + return a.replace(/./g, "0") + //return Math.pow(10, a.length - 1) //å°†æ’值表达å¼æ’å…¥10çš„N-1次方æ¥å ä½ + }) + var colonIndex = noExpr.indexOf(":") //å–得第一个冒å·çš„ä½ç½® + if (colonIndex === -1) { // 比如 ms-class="aaa bbb ccc" 的情况 + var className = text + } else { // 比如 ms-class-1="ui-state-active:checked" 的情况 + className = text.slice(0, colonIndex) + rightExpr = text.slice(colonIndex + 1) + parseExpr(rightExpr, vmodels, data) //决定是添加还是删除 + if (!data.evaluator) { + log("debug: ms-class '" + (rightExpr || "").trim() + "' ä¸å­˜åœ¨äºŽVM中") + return false + } else { + data._evaluator = data.evaluator + data._args = data.args + } + } + var hasExpr = rexpr.test(className) //比如ms-class="width{{w}}"的情况 + if (!hasExpr) { + data.immobileClass = className + } + parseExprProxy("", vmodels, data, (hasExpr ? scanExpr(className) : 0)) + } else { + data.immobileClass = data.oldStyle = data.param + parseExprProxy(text, vmodels, data) + } + } + + bindingExecutors["class"] = function (val, elem, data) { + var $elem = avalon(elem), + method = data.type + if (method === "class" && data.oldStyle) { //如果是旧风格 + $elem.toggleClass(data.oldStyle, !!val) + } else { + //如果存在冒å·å°±æœ‰æ±‚值函数 + data.toggleClass = data._evaluator ? !!data._evaluator.apply(elem, data._args) : true + data.newClass = data.immobileClass || val + if (data.oldClass && data.newClass !== data.oldClass) { + $elem.removeClass(data.oldClass) + } + data.oldClass = data.newClass + switch (method) { + case "class": + $elem.toggleClass(data.newClass, data.toggleClass) + break + case "hover": + case "active": + if (!data.hasBindEvent) { //ç¡®ä¿åªç»‘定一次 + var activate = "mouseenter" //在移出移入时切æ¢ç±»å + var abandon = "mouseleave" + if (method === "active") { //在èšç„¦å¤±ç„¦ä¸­åˆ‡æ¢ç±»å + elem.tabIndex = elem.tabIndex || -1 + activate = "mousedown" + abandon = "mouseup" + var fn0 = $elem.bind("mouseleave", function () { + data.toggleClass && $elem.removeClass(data.newClass) + }) + } + var fn1 = $elem.bind(activate, function () { + data.toggleClass && $elem.addClass(data.newClass) + }) + var fn2 = $elem.bind(abandon, function () { + data.toggleClass && $elem.removeClass(data.newClass) + }) + data.rollback = function () { + $elem.unbind("mouseleave", fn0) + $elem.unbind(activate, fn1) + $elem.unbind(abandon, fn2) + } + data.hasBindEvent = true + } + break; + } + } + } + + "hover,active".replace(rword, function (method) { + bindingHandlers[method] = bindingHandlers["class"] + }) +//ms-controller绑定已ç»åœ¨scanTag 方法中实现 +//ms-css绑定已由ms-attr绑定实现 + + +// bindingHandlers.data 定义在if.js + bindingExecutors.data = function (val, elem, data) { + var key = "data-" + data.param + if (val && typeof val === "object") { + elem[key] = val + } else { + elem.setAttribute(key, String(val)) + } + } +//åŒå·¥ç»‘定 + var duplexBinding = bindingHandlers.duplex = function (data, vmodels) { + var elem = data.element, + hasCast + parseExprProxy(data.value, vmodels, data, 0, 1) + + data.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop + if (data.evaluator && data.args) { + var params = [] + var casting = oneObject("string,number,boolean,checked") + if (elem.type === "radio" && data.param === "") { + data.param = "checked" + } + if (elem.msData) { + elem.msData["ms-duplex"] = data.value + } + data.param.replace(/\w+/g, function (name) { + if (/^(checkbox|radio)$/.test(elem.type) && /^(radio|checked)$/.test(name)) { + if (name === "radio") + log("ms-duplex-radioå·²ç»æ›´å为ms-duplex-checked") + name = "checked" + data.isChecked = true + } + if (name === "bool") { + name = "boolean" + log("ms-duplex-boolå·²ç»æ›´å为ms-duplex-boolean") + } else if (name === "text") { + name = "string" + log("ms-duplex-textå·²ç»æ›´å为ms-duplex-string") + } + if (casting[name]) { + hasCast = true + } + avalon.Array.ensure(params, name) + }) + if (!hasCast) { + params.push("string") + } + data.param = params.join("-") + data.bound = function (type, callback) { + if (elem.addEventListener) { + elem.addEventListener(type, callback, false) + } else { + elem.attachEvent("on" + type, callback) + } + var old = data.rollback + data.rollback = function () { + elem.avalonSetter = null + avalon.unbind(elem, type, callback) + old && old() + } + } + for (var i in avalon.vmodels) { + var v = avalon.vmodels[i] + v.$fire("avalon-ms-duplex-init", data) + } + var cpipe = data.pipe || (data.pipe = pipe) + cpipe(null, data, "init") + var tagName = elem.tagName + duplexBinding[tagName] && duplexBinding[tagName](elem, data.evaluator.apply(null, data.args), data) + } + } +//ä¸å­˜åœ¨ bindingExecutors.duplex + + function fixNull(val) { + return val == null ? "" : val + } + + avalon.duplexHooks = { + checked: { + get: function (val, data) { + return !data.element.oldValue + } + }, + string: { + get: function (val) { //åŒæ­¥åˆ°VM + return val + }, + set: fixNull + }, + "boolean": { + get: function (val) { + return val === "true" + }, + set: fixNull + }, + number: { + get: function (val, data) { + var number = parseFloat(val) + if (-val === -number) { + return number + } + var arr = /strong|medium|weak/.exec(data.element.getAttribute("data-duplex-number")) || ["medium"] + switch (arr[0]) { + case "strong": + return 0 + case "medium": + return val === "" ? "" : 0 + case "weak": + return val + } + }, + set: fixNull + } + } + + function pipe(val, data, action, e) { + data.param.replace(/\w+/g, function (name) { + var hook = avalon.duplexHooks[name] + if (hook && typeof hook[action] === "function") { + val = hook[action](val, data) + } + }) + return val + } + + var TimerID, ribbon = [] + + avalon.tick = function (fn) { + if (ribbon.push(fn) === 1) { + TimerID = setInterval(ticker, 60) + } + } + + function ticker() { + for (var n = ribbon.length - 1; n >= 0; n--) { + var el = ribbon[n] + if (el() === false) { + ribbon.splice(n, 1) + } + } + if (!ribbon.length) { + clearInterval(TimerID) + } + } + + var watchValueInTimer = noop + var rmsinput = /text|password|hidden/ + new function () { // jshint ignore:line + try { //#272 IE9-IE11, firefox + var setters = {} + var aproto = HTMLInputElement.prototype + var bproto = HTMLTextAreaElement.prototype + + function newSetter(value) { // jshint ignore:line + if (avalon.contains(root, this)) { + setters[this.tagName].call(this, value) + if (!rmsinput.test(this.type)) + return + if (!this.msFocus && this.avalonSetter) { + this.avalonSetter() + } + } + } + + var inputProto = HTMLInputElement.prototype + Object.getOwnPropertyNames(inputProto) //æ•…æ„引å‘IE6-8ç­‰æµè§ˆå™¨æŠ¥é”™ + setters["INPUT"] = Object.getOwnPropertyDescriptor(aproto, "value").set + Object.defineProperty(aproto, "value", { + set: newSetter + }) + setters["TEXTAREA"] = Object.getOwnPropertyDescriptor(bproto, "value").set + Object.defineProperty(bproto, "value", { + set: newSetter + }) + } catch (e) { + //在chrome 43中 ms-duplex终于ä¸éœ€è¦ä½¿ç”¨å®šæ—¶å™¨å®žçŽ°åŒå‘绑定了 + // http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype + // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1 + watchValueInTimer = avalon.tick + } + } // jshint ignore:line +//处ç†radio, checkbox, text, textarea, password + duplexBinding.INPUT = function (element, evaluator, data) { + var $type = element.type, + bound = data.bound, + $elem = avalon(element), + composing = false + + function callback(value) { + data.changed.call(this, value, data) + } + + function compositionStart() { + composing = true + } + + function compositionEnd() { + composing = false + } + + //当valueå˜åŒ–时改å˜model的值 + + var updateVModel = function () { + if (composing) //处ç†ä¸­æ–‡è¾“入法在minlengh下引å‘çš„BUG + return + var val = element.oldValue = element.value //防止递归调用形æˆæ­»å¾ªçŽ¯ + var lastValue = data.pipe(val, data, "get") + if ($elem.data("duplexObserve") !== false) { + evaluator(lastValue) + callback.call(element, lastValue) + if ($elem.data("duplex-focus")) { + avalon.nextTick(function () { + element.focus() + }) + } + } + } + //当modelå˜åŒ–æ—¶,它就会改å˜value的值 + data.handler = function () { + var val = data.pipe(evaluator(), data, "set") + "" + if (val !== element.oldValue) { + element.value = val + } + } + if (data.isChecked || $type === "radio") { + updateVModel = function () { + if ($elem.data("duplexObserve") !== false) { + var lastValue = data.pipe(element.value, data, "get") + evaluator(lastValue) + callback.call(element, lastValue) + } + } + data.handler = function () { + var val = evaluator() + var checked = data.isChecked ? !!val : val + "" === element.value + element.checked = element.oldValue = checked + } + bound("click", updateVModel) + } else if ($type === "checkbox") { + updateVModel = function () { + if ($elem.data("duplexObserve") !== false) { + var method = element.checked ? "ensure" : "remove" + var array = evaluator() + if (!Array.isArray(array)) { + log("ms-duplex应用于checkbox上è¦å¯¹åº”一个数组") + array = [array] + } + avalon.Array[method](array, data.pipe(element.value, data, "get")) + callback.call(element, array) + } + } + data.handler = function () { + var array = [].concat(evaluator()) //强制转æ¢ä¸ºæ•°ç»„ + element.checked = array.indexOf(data.pipe(element.value, data, "get")) > -1 + } + bound("change", updateVModel) + } else { + var events = element.getAttribute("data-duplex-event") || "input" + if (element.attributes["data-event"]) { + log("data-event指令已ç»åºŸå¼ƒï¼Œè¯·æ”¹ç”¨data-duplex-event") + } + events.replace(rword, function (name) { + switch (name) { + case "input": + bound("input", updateVModel) + bound("DOMAutoComplete", updateVModel) + if (!IEVersion) { + bound("compositionstart", compositionStart) + bound("compositionend", compositionEnd) + } + break + default: + bound(name, updateVModel) + break + } + }) + bound("focus", function () { + element.msFocus = true + }) + bound("blur", function () { + element.msFocus = false + }) + if (rmsinput.test($type)) { + watchValueInTimer(function () { + if (root.contains(element)) { + if (!element.msFocus && element.oldValue !== element.value) { + updateVModel() + } + } else if (!element.msRetain) { + return false + } + }) + } + + element.avalonSetter = updateVModel + } + + element.oldValue = element.value + avalon.injectBinding(data) + callback.call(element, element.value) + } + duplexBinding.TEXTAREA = duplexBinding.INPUT + duplexBinding.SELECT = function (element, evaluator, data) { + var $elem = avalon(element) + + function updateVModel() { + if ($elem.data("duplexObserve") !== false) { + var val = $elem.val() //字符串或字符串数组 + if (Array.isArray(val)) { + val = val.map(function (v) { + return data.pipe(v, data, "get") + }) + } else { + val = data.pipe(val, data, "get") + } + if (val + "" !== element.oldValue) { + evaluator(val) + } + data.changed.call(element, val, data) + } + } + + data.handler = function () { + var val = evaluator() + val = val && val.$model || val + if (Array.isArray(val)) { + if (!element.multiple) { + log("ms-duplex在ä¸èƒ½å¯¹åº”一个数组") + } + } + //å¿…é¡»å˜æˆå­—符串åŽæ‰èƒ½æ¯”较 + val = Array.isArray(val) ? val.map(String) : val + "" + if (val + "" !== element.oldValue) { + $elem.val(val) + element.oldValue = val + "" + } + } + data.bound("change", updateVModel) + element.msCallback = function () { + avalon.injectBinding(data) + data.changed.call(element, evaluator(), data) + } + } +// bindingHandlers.html 定义在if.js + bindingExecutors.html = function (val, elem, data) { + val = val == null ? "" : val + var isHtmlFilter = "group" in data + var parent = isHtmlFilter ? elem.parentNode : elem + if (!parent) + return + if (typeof val === "string") { + var fragment = avalon.parseHTML(val) + } else if (val.nodeType === 11) { //å°†val转æ¢ä¸ºæ–‡æ¡£ç¢Žç‰‡ + fragment = val + } else if (val.nodeType === 1 || val.item) { + var nodes = val.nodeType === 1 ? val.childNodes : val.item + fragment = hyperspace.cloneNode(true) + while (nodes[0]) { + fragment.appendChild(nodes[0]) + } + } + if (!fragment.firstChild) { + fragment.appendChild(DOC.createComment("ms-html")) + } + nodes = avalon.slice(fragment.childNodes) + //æ’å…¥å ä½ç¬¦, 如果是过滤器,需è¦æœ‰èŠ‚制地移除指定的数é‡,如果是html指令,直接清空 + if (isHtmlFilter) { + var n = data.group, + i = 1 + + data.group = nodes.length + data.element = nodes[0] + + while (i < n) { + var node = elem.nextSibling + if (node) { + parent.removeChild(node) + i++ + } + } + parent.replaceChild(fragment, elem) + } else { + avalon.clearHTML(parent).appendChild(fragment) + } + scanNodeArray(nodes, data.vmodels) + } + bindingHandlers["if"] = + bindingHandlers.data = + bindingHandlers.text = + bindingHandlers.html = + function (data, vmodels) { + parseExprProxy(data.value, vmodels, data) + } + + bindingExecutors["if"] = function (val, elem, data) { + if (val) { //æ’回DOMæ ‘ + if (elem.nodeType === 8) { + elem.parentNode.replaceChild(data.template, elem) + elem = data.element = data.template //这时å¯èƒ½ä¸ºnull + } + if (elem.getAttribute(data.name)) { + elem.removeAttribute(data.name) + scanAttr(elem, data.vmodels) + } + data.rollback = null + } else { //移出DOM树,并用注释节点å æ®åŽŸä½ç½® + if (elem.nodeType === 1) { + var node = data.element = DOC.createComment("ms-if") + elem.parentNode.replaceChild(node, elem) + data.template = elem //元素节点 + ifGroup.appendChild(elem) + data.rollback = function () { + if (elem.parentNode === ifGroup) { + ifGroup.removeChild(elem) + } + } + } + } + } +//ms-important绑定已ç»åœ¨scanTag 方法中实现 +//ms-include绑定已由ms-attr绑定实现 + + var rdash = /\(([^)]*)\)/ + bindingHandlers.on = function (data, vmodels) { + var value = data.value + data.type = "on" + var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10 + if (typeof bindingHandlers.on[eventType + "Hook"] === "function") { + bindingHandlers.on[eventType + "Hook"](data) + } + if (value.indexOf("(") > 0 && value.indexOf(")") > -1) { + var matched = (value.match(rdash) || ["", ""])[1].trim() + if (matched === "" || matched === "$event") { // aaa() aaa($event)当æˆaaaå¤„ç† + value = value.replace(rdash, "") + } + } + parseExprProxy(value, vmodels, data) + } + + bindingExecutors.on = function (callback, elem, data) { + callback = function (e) { + var fn = data.evaluator || noop + return fn.apply(this, data.args.concat(e)) + } + var eventType = data.param.replace(/-\d+$/, "") // ms-on-mousemove-10 + if (eventType === "scan") { + callback.call(elem, { + type: eventType + }) + } else if (typeof data.specialBind === "function") { + data.specialBind(elem, callback) + } else { + var removeFn = avalon.bind(elem, eventType, callback) + } + data.rollback = function () { + if (typeof data.specialUnbind === "function") { + data.specialUnbind() + } else { + avalon.unbind(elem, eventType, removeFn) + } + } + } + bindingHandlers.repeat = function (data, vmodels) { + var type = data.type + parseExprProxy(data.value, vmodels, data, 0, 1) + var freturn = false + try { + var $repeat = data.$repeat = data.evaluator.apply(0, data.args || []) + var xtype = avalon.type($repeat) + if (xtype !== "object" && xtype !== "array") { + freturn = true + avalon.log("warning:" + data.value + "åªèƒ½æ˜¯å¯¹è±¡æˆ–数组") + } + } catch (e) { + freturn = true + } + + var arr = data.value.split(".") || [] + if (arr.length > 1) { + arr.pop() + var n = arr[0] + for (var i = 0, v; v = vmodels[i++];) { + if (v && v.hasOwnProperty(n)) { + var events = v[n].$events || {} + events[subscribers] = events[subscribers] || [] + events[subscribers].push(data) + break + } + } + } + var elem = data.element + elem.removeAttribute(data.name) + + data.sortedCallback = getBindingCallback(elem, "data-with-sorted", vmodels) + data.renderedCallback = getBindingCallback(elem, "data-" + type + "-rendered", vmodels) + var signature = generateID(type) + var comment = data.element = DOC.createComment(signature + ":end") + data.clone = DOC.createComment(signature) + hyperspace.appendChild(comment) + + if (type === "each" || type === "with") { + data.template = elem.innerHTML.trim() + avalon.clearHTML(elem).appendChild(comment) + } else { + data.template = elem.outerHTML.trim() + elem.parentNode.replaceChild(comment, elem) + } + data.template = avalon.parseHTML(data.template) + data.rollback = function () { + var elem = data.element + if (!elem) + return + bindingExecutors.repeat.call(data, "clear") + var parentNode = elem.parentNode + var content = data.template + var target = content.firstChild + parentNode.replaceChild(content, elem) + var start = data.$with + start && start.parentNode && start.parentNode.removeChild(start) + target = data.element = data.type === "repeat" ? target : parentNode + } + if (freturn) { + return + } + data.handler = bindingExecutors.repeat + data.$outer = {} + var check0 = "$key" + var check1 = "$val" + if (Array.isArray($repeat)) { + $repeat.$map[data.param || "el"] = 1 + check0 = "$first" + check1 = "$last" + } + for (i = 0; v = vmodels[i++];) { + if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) { + data.$outer = v + break + } + } + var $events = $repeat.$events + var $list = ($events || {})[subscribers] + if ($list && avalon.Array.ensure($list, data)) { + addSubscribers(data, $list) + } + if (xtype === "object") { + data.$with = true + var pool = !$events ? {} : $events.$withProxyPool || ($events.$withProxyPool = {}) + data.handler("append", $repeat, pool) + } else if ($repeat.length) { + data.handler("add", 0, $repeat.length) + } + } + + bindingExecutors.repeat = function (method, pos, el) { + if (method) { + var data = this, start, fragment + var end = data.element + var comments = getComments(data) + var parent = end.parentNode + var transation = hyperspace.cloneNode(false) + switch (method) { + case "add": //在posä½ç½®åŽæ·»åŠ el数组(pos为æ’å…¥ä½ç½®,el为è¦æ’入的个数) + var n = pos + el + var fragments = [] + var array = data.$repeat + for (var i = pos; i < n; i++) { + var proxy = array.$proxy[i] + proxy.$outer = data.$outer + shimController(data, transation, proxy, fragments) + } + parent.insertBefore(transation, comments[pos] || end) + for (i = 0; fragment = fragments[i++];) { + scanNodeArray(fragment.nodes, fragment.vmodels) + fragment.nodes = fragment.vmodels = null + } + break + case "del": //å°†posåŽçš„el个元素删掉(pos, el都是数字) + sweepNodes(comments[pos], comments[pos + el] || end) + break + case "clear": + start = comments[0] + if (start) { + sweepNodes(start, end) + } + break + case "move": + start = comments[0] + if (start) { + var signature = start.nodeValue + var rooms = [] + var room = [], + node + sweepNodes(start, end, function () { + room.unshift(this) + if (this.nodeValue === signature) { + rooms.unshift(room) + room = [] + } + }) + sortByIndex(rooms, pos) + while (room = rooms.shift()) { + while (node = room.shift()) { + transation.appendChild(node) + } + } + parent.insertBefore(transation, end) + } + break + case "append": //å°†pos的键值对从el中å–出(pos为一个普通对象,el为预先生æˆå¥½çš„代ç†VM对象池) + var pool = el + var keys = [] + fragments = [] + for (var key in pos) { //得到所有键å + if (pos.hasOwnProperty(key) && key !== "hasOwnProperty") { + keys.push(key) + } + } + if (data.sortedCallback) { //å¦‚æžœæœ‰å›žè°ƒï¼Œåˆ™è®©å®ƒä»¬æŽ’åº + var keys2 = data.sortedCallback.call(parent, keys) + if (keys2 && Array.isArray(keys2) && keys2.length) { + keys = keys2 + } + } + for (i = 0; key = keys[i++];) { + if (key !== "hasOwnProperty") { + if (!pool[key]) { + pool[key] = withProxyAgent(key, data) + } + shimController(data, transation, pool[key], fragments) + } + } + var comment = data.$with = data.clone + parent.insertBefore(comment, end) + parent.insertBefore(transation, end) + for (i = 0; fragment = fragments[i++];) { + scanNodeArray(fragment.nodes, fragment.vmodels) + fragment.nodes = fragment.vmodels = null + } + break + } + if (method === "clear") + method = "del" + var callback = data.renderedCallback || noop, + args = arguments + checkScan(parent, function () { + callback.apply(parent, args) + if (parent.oldValue && parent.tagName === "SELECT") { //fix #503 + avalon(parent).val(parent.oldValue.split(",")) + } + }, NaN) + } + } + + "with,each".replace(rword, function (name) { + bindingHandlers[name] = bindingHandlers.repeat + }) + + function shimController(data, transation, proxy, fragments) { + var content = data.template.cloneNode(true) + var nodes = avalon.slice(content.childNodes) + if (!data.$with) { + content.insertBefore(data.clone.cloneNode(false), content.firstChild) + } + transation.appendChild(content) + var nv = [proxy].concat(data.vmodels) + var fragment = { + nodes: nodes, + vmodels: nv + } + fragments.push(fragment) + } + + function getComments(data) { + var end = data.element + var signature = end.nodeValue.replace(":end", "") + var node = end.previousSibling + var array = [] + while (node) { + if (node.nodeValue === signature) { + array.unshift(node) + } + node = node.previousSibling + } + return array + } + + +//移除掉start与end之间的节点(ä¿ç•™end) + function sweepNodes(start, end, callback) { + while (true) { + var node = end.previousSibling + if (!node) + break + node.parentNode.removeChild(node) + callback && callback.call(node) + if (node === start) { + break + } + } + } + +// 为ms-each,ms-with, ms-repeat会创建一个代ç†VM, +// 通过它们ä¿æŒä¸€ä¸ªä¸‹ä¸Šæ–‡ï¼Œè®©ç”¨æˆ·èƒ½è°ƒç”¨$index,$first,$last,$remove,$key,$val,$outer等属性与方法 +// 所有代ç†VM的产生,消费,收集,存放通过xxxProxyFactory,xxxProxyAgent, recycleProxies,xxxProxyPool实现 + var eachProxyPool = [] + var withProxyPool = [] + + function eachProxyFactory() { + var source = { + $index: 0, + $first: false, + $last: false, + $map: {}, + $host: [], + $outer: {}, + $remove: avalon.noop, + el: { + get: function () { + var e = this.$events + var array = e.$index + e.$index = e.el //#817 通过$index为el收集ä¾èµ– + try { + return this.$host[this.$index] + } finally { + e.$index = array + } + }, + set: function (val) { + this.$host.set(this.$index, val) + } + } + } + + var second = { + $last: 1, + $first: 1, + $index: 1 + } + var proxy = modelFactory(source, second) + proxy.$id = generateID("$proxy$each") + return proxy + } + + function eachProxyAgent(index, host) { + var proxy = eachProxyPool.shift() + if (!proxy) { + proxy = eachProxyFactory() + } + var last = host.length - 1 + proxy.$index = index + proxy.$first = index === 0 + proxy.$last = index === last + proxy.$map = host.$map + proxy.$host = host + proxy.$remove = function () { + return host.removeAt(proxy.$index) + } + return proxy + } + + function withProxyFactory() { + var proxy = modelFactory({ + $key: "", + $outer: {}, + $host: {}, + $val: { + get: function () { + return this.$host[this.$key] + }, + set: function (val) { + this.$host[this.$key] = val + } + } + }, { + $val: 1 + }) + proxy.$id = generateID("$proxy$with") + return proxy + } + + function withProxyAgent(key, data) { + var proxy = withProxyPool.pop() + if (!proxy) { + proxy = withProxyFactory() + } + var host = data.$repeat + proxy.$key = key + proxy.$host = host + proxy.$outer = data.$outer + if (host.$events) { + proxy.$events.$val = host.$events[key] + } else { + proxy.$events = {} + } + return proxy + } + + function recycleProxies(proxies, type) { + var proxyPool = type === "each" ? eachProxyPool : withProxyPool + avalon.each(proxies, function (key, proxy) { + if (proxy.$events) { + for (var i in proxy.$events) { + if (Array.isArray(proxy.$events[i])) { + proxy.$events[i].forEach(function (data) { + if (typeof data === "object") + disposeData(data) + }) // jshint ignore:line + proxy.$events[i].length = 0 + } + } + proxy.$host = proxy.$outer = {} + if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) { + proxyPool.pop() + } + } + }) + if (type === "each") + proxies.length = 0 + } + + /********************************************************************* + * å„ç§æŒ‡ä»¤ * + **********************************************************************/ +//ms-skip绑定已ç»åœ¨scanTag 方法中实现 +// bindingHandlers.text 定义在if.js + bindingExecutors.text = function (val, elem) { + val = val == null ? "" : val //ä¸åœ¨é¡µé¢ä¸Šæ˜¾ç¤ºundefined null + if (elem.nodeType === 3) { //绑定在文本节点上 + try { //IE对游离于DOM树外的节点赋值会报错 + elem.data = val + } catch (e) { + } + } else { //绑定在特性节点上 + elem.textContent = val + } + } + function parseDisplay(nodeName, val) { + //用于å–得此类标签的默认display值 + var key = "_" + nodeName + if (!parseDisplay[key]) { + var node = DOC.createElement(nodeName) + root.appendChild(node) + if (W3C) { + val = getComputedStyle(node, null).display + } else { + val = node.currentStyle.display + } + root.removeChild(node) + parseDisplay[key] = val + } + return parseDisplay[key] + } + + avalon.parseDisplay = parseDisplay + + bindingHandlers.visible = function (data, vmodels) { + var elem = avalon(data.element) + var display = elem.css("display") + if (display === "none") { + var style = elem[0].style + var has = /visibility/i.test(style.cssText) + var visible = elem.css("visibility") + style.display = "" + style.visibility = "hidden" + display = elem.css("display") + if (display === "none") { + display = parseDisplay(elem[0].nodeName) + } + style.visibility = has ? visible : "" + } + data.display = display + parseExprProxy(data.value, vmodels, data) + } + + bindingExecutors.visible = function (val, elem, data) { + elem.style.display = val ? data.display : "none" + } + bindingHandlers.widget = function (data, vmodels) { + var args = data.value.match(rword) + var elem = data.element + var widget = args[0] + var id = args[1] + if (!id || id === "$") { //没有定义或为$时,å–组件å+éšæœºæ•° + id = generateID(widget) + } + var optName = args[2] || widget //没有定义,å–组件å + var constructor = avalon.ui[widget] + if (typeof constructor === "function") { //ms-widget="tabs,tabsAAA,optname" + vmodels = elem.vmodels || vmodels + for (var i = 0, v; v = vmodels[i++];) { + if (v.hasOwnProperty(optName) && typeof v[optName] === "object") { + var vmOptions = v[optName] + vmOptions = vmOptions.$model || vmOptions + break + } + } + if (vmOptions) { + var wid = vmOptions[widget + "Id"] + if (typeof wid === "string") { + log("warning!ä¸å†æ”¯æŒ" + widget + "Id") + id = wid + } + } + //抽å–data-tooltip-textã€data-tooltip-attr属性,组æˆä¸€ä¸ªé…置对象 + var widgetData = avalon.getWidgetData(elem, widget) + data.value = [widget, id, optName].join(",") + data[widget + "Id"] = id + data.evaluator = noop + elem.msData["ms-widget-id"] = id + var options = data[widget + "Options"] = avalon.mix({}, constructor.defaults, vmOptions || {}, widgetData) + elem.removeAttribute("ms-widget") + var vmodel = constructor(elem, data, vmodels) || {} //防止组件ä¸è¿”回VM + if (vmodel.$id) { + avalon.vmodels[id] = vmodel + createSignalTower(elem, vmodel) + try { + vmodel.$init(function () { + avalon.scan(elem, [vmodel].concat(vmodels)) + if (typeof options.onInit === "function") { + options.onInit.call(elem, vmodel, options, vmodels) + } + }) + } catch (e) { + } + data.rollback = function () { + try { + vmodel.widgetElement = null + vmodel.$remove() + } catch (e) { + } + elem.msData = {} + delete avalon.vmodels[vmodel.$id] + } + addSubscribers(data, widgetList) + if (window.chrome) { + elem.addEventListener("DOMNodeRemovedFromDocument", function () { + setTimeout(removeSubscribers) + }) + } + } else { + avalon.scan(elem, vmodels) + } + } else if (vmodels.length) { //如果该组件还没有加载,那么ä¿å­˜å½“å‰çš„vmodels + elem.vmodels = vmodels + } + } + var widgetList = [] +//ä¸å­˜åœ¨ bindingExecutors.widget + /********************************************************************* + * 自带过滤器 * + **********************************************************************/ + var rscripts = /]*>([\S\s]*?)<\/script\s*>/gim + var ron = /\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g + var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig + var rsanitize = { + a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig, + img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig, + form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig + } + var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g + var rnoalphanumeric = /([^\#-~| |!])/g; + + function numberFormat(number, decimals, point, thousands) { + //form http://phpjs.org/functions/number_format/ + //number 必需,è¦æ ¼å¼åŒ–çš„æ•°å­— + //decimals å¯é€‰ï¼Œè§„定多少个å°æ•°ä½ã€‚ + //point å¯é€‰ï¼Œè§„定用作å°æ•°ç‚¹çš„字符串(默认为 . )。 + //thousands å¯é€‰ï¼Œè§„定用作åƒä½åˆ†éš”符的字符串(默认为 , ),如果设置了该å‚数,那么所有其他å‚数都是必需的。 + number = (number + '') + .replace(/[^0-9+\-Ee.]/g, '') + var n = !isFinite(+number) ? 0 : +number, + prec = !isFinite(+decimals) ? 3 : Math.abs(decimals), + sep = thousands || ",", + dec = point || ".", + s = '', + toFixedFix = function (n, prec) { + var k = Math.pow(10, prec) + return '' + (Math.round(n * k) / k) + .toFixed(prec) + } + // Fix for IE parseFloat(0.55).toFixed(0) = 0; + s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)) + .split('.') + if (s[0].length > 3) { + s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep) + } + if ((s[1] || '') + .length < prec) { + s[1] = s[1] || '' + s[1] += new Array(prec - s[1].length + 1) + .join('0') + } + return s.join(dec) + } + + + var filters = avalon.filters = { + uppercase: function (str) { + return str.toUpperCase() + }, + lowercase: function (str) { + return str.toLowerCase() + }, + truncate: function (str, length, truncation) { + //length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串 + length = length || 30 + truncation = truncation === void(0) ? "..." : truncation + return str.length > length ? str.slice(0, length - truncation.length) + truncation : String(str) + }, + $filter: function (val) { + for (var i = 1, n = arguments.length; i < n; i++) { + var array = arguments[i] + var fn = avalon.filters[array.shift()] + if (typeof fn === "function") { + var arr = [val].concat(array) + val = fn.apply(null, arr) + } + } + return val + }, + camelize: camelize, + //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet + // chrome + // chrome + // IE67chrome + // IE67chrome + // IE67chrome + sanitize: function (str) { + return str.replace(rscripts, "").replace(ropen, function (a, b) { + var match = a.toLowerCase().match(/<(\w+)\s/) + if (match) { //处ç†a标签的href属性,img标签的src属性,form标签的action属性 + var reg = rsanitize[match[1]] + if (reg) { + a = a.replace(reg, function (s, name, value) { + var quote = value.charAt(0) + return name + "=" + quote + "javascript:void(0)" + quote// jshint ignore:line + }) + } + } + return a.replace(ron, " ").replace(/\s+/g, " ") //移除onXXX事件 + }) + }, + escape: function (str) { + //将字符串ç»è¿‡ str 转义得到适åˆåœ¨é¡µé¢ä¸­æ˜¾ç¤ºçš„内容, ä¾‹å¦‚æ›¿æ¢ < 为 < + return String(str). + replace(/&/g, '&'). + replace(rsurrogate, function (value) { + var hi = value.charCodeAt(0) + var low = value.charCodeAt(1) + return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';' + }). + replace(rnoalphanumeric, function (value) { + return '&#' + value.charCodeAt(0) + ';' + }). + replace(//g, '>') + }, + currency: function (amount, symbol, fractionSize) { + return (symbol || "\uFFE5") + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2) + }, + number: numberFormat + } + /* + 'yyyy': 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010) + 'yy': 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) + 'y': 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199) + 'MMMM': Month in year (January-December) + 'MMM': Month in year (Jan-Dec) + 'MM': Month in year, padded (01-12) + 'M': Month in year (1-12) + 'dd': Day in month, padded (01-31) + 'd': Day in month (1-31) + 'EEEE': Day in Week,(Sunday-Saturday) + 'EEE': Day in Week, (Sun-Sat) + 'HH': Hour in day, padded (00-23) + 'H': Hour in day (0-23) + 'hh': Hour in am/pm, padded (01-12) + 'h': Hour in am/pm, (1-12) + 'mm': Minute in hour, padded (00-59) + 'm': Minute in hour (0-59) + 'ss': Second in minute, padded (00-59) + 's': Second in minute (0-59) + 'a': am/pm marker + 'Z': 4 digit (+sign) representation of the timezone offset (-1200-+1200) + format string can also be one of the following predefined localizable formats: + + 'medium': equivalent to 'MMM d, y h:mm:ss a' for en_US locale (e.g. Sep 3, 2010 12:05:08 pm) + 'short': equivalent to 'M/d/yy h:mm a' for en_US locale (e.g. 9/3/10 12:05 pm) + 'fullDate': equivalent to 'EEEE, MMMM d,y' for en_US locale (e.g. Friday, September 3, 2010) + 'longDate': equivalent to 'MMMM d, y' for en_US locale (e.g. September 3, 2010 + 'mediumDate': equivalent to 'MMM d, y' for en_US locale (e.g. Sep 3, 2010) + 'shortDate': equivalent to 'M/d/yy' for en_US locale (e.g. 9/3/10) + 'mediumTime': equivalent to 'h:mm:ss a' for en_US locale (e.g. 12:05:08 pm) + 'shortTime': equivalent to 'h:mm a' for en_US locale (e.g. 12:05 pm) + */ + new function () {// jshint ignore:line + function toInt(str) { + return parseInt(str, 10) || 0 + } + + function padNumber(num, digits, trim) { + var neg = "" + if (num < 0) { + neg = '-' + num = -num + } + num = "" + num + while (num.length < digits) + num = "0" + num + if (trim) + num = num.substr(num.length - digits) + return neg + num + } + + function dateGetter(name, size, offset, trim) { + return function (date) { + var value = date["get" + name]() + if (offset > 0 || value > -offset) + value += offset + if (value === 0 && offset === -12) { + value = 12 + } + return padNumber(value, size, trim) + } + } + + function dateStrGetter(name, shortForm) { + return function (date, formats) { + var value = date["get" + name]() + var get = (shortForm ? ("SHORT" + name) : name).toUpperCase() + return formats[get][value] + } + } + + function timeZoneGetter(date) { + var zone = -1 * date.getTimezoneOffset() + var paddedZone = (zone >= 0) ? "+" : "" + paddedZone += padNumber(Math[zone > 0 ? "floor" : "ceil"](zone / 60), 2) + padNumber(Math.abs(zone % 60), 2) + return paddedZone + } + + //å–得上åˆä¸‹åˆ + + function ampmGetter(date, formats) { + return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1] + } + + var DATE_FORMATS = { + yyyy: dateGetter("FullYear", 4), + yy: dateGetter("FullYear", 2, 0, true), + y: dateGetter("FullYear", 1), + MMMM: dateStrGetter("Month"), + MMM: dateStrGetter("Month", true), + MM: dateGetter("Month", 2, 1), + M: dateGetter("Month", 1, 1), + dd: dateGetter("Date", 2), + d: dateGetter("Date", 1), + HH: dateGetter("Hours", 2), + H: dateGetter("Hours", 1), + hh: dateGetter("Hours", 2, -12), + h: dateGetter("Hours", 1, -12), + mm: dateGetter("Minutes", 2), + m: dateGetter("Minutes", 1), + ss: dateGetter("Seconds", 2), + s: dateGetter("Seconds", 1), + sss: dateGetter("Milliseconds", 3), + EEEE: dateStrGetter("Day"), + EEE: dateStrGetter("Day", true), + a: ampmGetter, + Z: timeZoneGetter + } + var rdateFormat = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/ + var raspnetjson = /^\/Date\((\d+)\)\/$/ + filters.date = function (date, format) { + var locate = filters.date.locate, + text = "", + parts = [], + fn, match + format = format || "mediumDate" + format = locate[format] || format + if (typeof date === "string") { + if (/^\d+$/.test(date)) { + date = toInt(date) + } else if (raspnetjson.test(date)) { + date = +RegExp.$1 + } else { + var trimDate = date.trim() + var dateArray = [0, 0, 0, 0, 0, 0, 0] + var oDate = new Date(0) + //å–得年月日 + trimDate = trimDate.replace(/^(\d+)\D(\d+)\D(\d+)/, function (_, a, b, c) { + var array = c.length === 4 ? [c, a, b] : [a, b, c] + dateArray[0] = toInt(array[0]) //å¹´ + dateArray[1] = toInt(array[1]) - 1 //月 + dateArray[2] = toInt(array[2]) //æ—¥ + return "" + }) + var dateSetter = oDate.setFullYear + var timeSetter = oDate.setHours + trimDate = trimDate.replace(/[T\s](\d+):(\d+):?(\d+)?\.?(\d)?/, function (_, a, b, c, d) { + dateArray[3] = toInt(a) //å°æ—¶ + dateArray[4] = toInt(b) //分钟 + dateArray[5] = toInt(c) //秒 + if (d) { //毫秒 + dateArray[6] = Math.round(parseFloat("0." + d) * 1000) + } + return "" + }) + var tzHour = 0 + var tzMin = 0 + trimDate = trimDate.replace(/Z|([+-])(\d\d):?(\d\d)/, function (z, symbol, c, d) { + dateSetter = oDate.setUTCFullYear + timeSetter = oDate.setUTCHours + if (symbol) { + tzHour = toInt(symbol + c) + tzMin = toInt(symbol + d) + } + return "" + }) + + dateArray[3] -= tzHour + dateArray[4] -= tzMin + dateSetter.apply(oDate, dateArray.slice(0, 3)) + timeSetter.apply(oDate, dateArray.slice(3)) + date = oDate + } + } + if (typeof date === "number") { + date = new Date(date) + } + if (avalon.type(date) !== "date") { + return + } + while (format) { + match = rdateFormat.exec(format) + if (match) { + parts = parts.concat(match.slice(1)) + format = parts.pop() + } else { + parts.push(format) + format = null + } + } + parts.forEach(function (value) { + fn = DATE_FORMATS[value] + text += fn ? fn(date, locate) : value.replace(/(^'|'$)/g, "").replace(/''/g, "'") + }) + return text + } + var locate = { + AMPMS: { + 0: "上åˆ", + 1: "下åˆ" + }, + DAY: { + 0: "星期日", + 1: "星期一", + 2: "星期二", + 3: "星期三", + 4: "星期四", + 5: "星期五", + 6: "星期六" + }, + MONTH: { + 0: "1月", + 1: "2月", + 2: "3月", + 3: "4月", + 4: "5月", + 5: "6月", + 6: "7月", + 7: "8月", + 8: "9月", + 9: "10月", + 10: "11月", + 11: "12月" + }, + SHORTDAY: { + "0": "周日", + "1": "周一", + "2": "周二", + "3": "周三", + "4": "周四", + "5": "周五", + "6": "周六" + }, + fullDate: "yå¹´M月dæ—¥EEEE", + longDate: "yå¹´M月dæ—¥", + medium: "yyyy-M-d H:mm:ss", + mediumDate: "yyyy-M-d", + mediumTime: "H:mm:ss", + "short": "yy-M-d ah:mm", + shortDate: "yy-M-d", + shortTime: "ah:mm" + } + locate.SHORTMONTH = locate.MONTH + filters.date.locate = locate + }// jshint ignore:line + /********************************************************************* + * AMD加载器 * + **********************************************************************/ +//https://www.devbridge.com/articles/understanding-amd-requirejs/ +//http://maxogden.com/nested-dependencies.html + var modules = avalon.modules = { + "domReady!": { + exports: avalon, + state: 3 + }, + "avalon": { + exports: avalon, + state: 4 + } + } +//Object(modules[id]).state拥有如下值 +// undefined 没有定义 +// 1(send) å·²ç»å‘出请求 +// 2(loading) å·²ç»è¢«æ‰§è¡Œä½†è¿˜æ²¡æœ‰æ‰§è¡Œå®Œæˆï¼Œåœ¨è¿™ä¸ªé˜¶æ®µdefine方法会被执行 +// 3(loaded) 执行完毕,通过onload/onreadystatechange回调判定,在这个阶段checkDeps方法会执行 +// 4(execute) å…¶ä¾èµ–也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行 + modules.exports = modules.avalon + + new function () {// jshint ignore:line + var loadings = [] //正在加载中的模å—列表 + var factorys = [] //放置define方法的factory函数 + var rjsext = /\.js$/i + + function makeRequest(name, config) { +//1. 去掉资æºå‰ç¼€ + var res = "js" + name = name.replace(/^(\w+)\!/, function (a, b) { + res = b + return "" + }) + if (res === "ready") { + log("debug: ready!å·²ç»è¢«åºŸå¼ƒï¼Œè¯·ä½¿ç”¨domReady!") + res = "domReady" + } +//2. 去掉querystring, hash + var query = "" + name = name.replace(rquery, function (a) { + query = a + return "" + }) + //3. 去掉扩展å + var suffix = "." + res + var ext = /js|css/.test(suffix) ? suffix : "" + name = name.replace(/\.[a-z0-9]+$/g, function (a) { + if (a === suffix) { + ext = a + return "" + } else { + return a + } + }) + var req = avalon.mix({ + query: query, + ext: ext, + res: res, + name: name, + toUrl: toUrl + }, config) + req.toUrl(name) + return req + } + + function fireRequest(req) { + var name = req.name + var res = req.res + //1. 如果该模å—å·²ç»å‘出请求,直接返回 + var module = modules[name] + var urlNoQuery = name && req.urlNoQuery + if (module && module.state >= 1) { + return name + } + module = modules[urlNoQuery] + if (module && module.state >= 3) { + innerRequire(module.deps || [], module.factory, urlNoQuery) + return urlNoQuery + } + if (name && !module) { + module = modules[urlNoQuery] = { + id: urlNoQuery, + state: 1 //send + } + var wrap = function (obj) { + resources[res] = obj + obj.load(name, req, function (a) { + if (arguments.length && a !== void 0) { + module.exports = a + } + module.state = 4 + checkDeps() + }) + } + + if (!resources[res]) { + innerRequire([res], wrap) + } else { + wrap(resources[res]) + } + } + return name ? urlNoQuery : res + "!" + } + +//核心API之一 require + var requireQueue = [] + var isUserFirstRequire = false + innerRequire = avalon.require = function (array, factory, parentUrl, defineConfig) { + if (!isUserFirstRequire) { + requireQueue.push(avalon.slice(arguments)) + if (arguments.length <= 2) { + isUserFirstRequire = true + var queue = requireQueue.splice(0, requireQueue.length), args + while (args = queue.shift()) { + innerRequire.apply(null, args) + } + } + return + } + + if (!Array.isArray(array)) { + avalon.error("require方法的第一个å‚数应为数组 " + array) + } + var deps = [] // 放置所有ä¾èµ–项的完整路径 + var uniq = createMap() + var id = parentUrl || "callback" + setTimeout("1")// jshint ignore:line + defineConfig = defineConfig || createMap() + defineConfig.baseUrl = kernel.baseUrl + var isBuilt = !!defineConfig.built + if (parentUrl) { + defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf("/")) + defineConfig.mapUrl = parentUrl.replace(rjsext, "") + } + if (isBuilt) { + var req = makeRequest(defineConfig.defineName, defineConfig) + id = req.urlNoQuery + } else { + array.forEach(function (name) { + var req = makeRequest(name, defineConfig) + var url = fireRequest(req) //加载资æºï¼Œå¹¶è¿”回该资æºçš„å®Œæ•´åœ°å€ + if (url) { + if (!uniq[url]) { + deps.push(url) + uniq[url] = "å¸å¾’正美" //åŽ»é‡ + } + } + }) + } + + var module = modules[id] + if (!module || module.state !== 4) { + modules[id] = { + id: id, + deps: isBuilt ? array.concat() : deps, + factory: factory || noop, + state: 3 + } + } + if (!module) { + //如果此模å—是定义在å¦ä¸€ä¸ªJS文件中, 那必须等该文件加载完毕, æ‰èƒ½æ”¾åˆ°æ£€æµ‹åˆ—队中 + loadings.push(id) + } + checkDeps() + } + +//核心API之二 require + innerRequire.define = function (name, deps, factory) { //模å—å,ä¾èµ–列表,模å—本身 + if (typeof name !== "string") { + factory = deps + deps = name + name = "anonymous" + } + if (!Array.isArray(deps)) { + factory = deps + deps = [] + } + var config = { + built: !isUserFirstRequire, //用r.js打包åŽ,所有define会放到requirejsä¹‹å‰ + defineName: name + } + var args = [deps, factory, config] + factory.require = function (url) { + args.splice(2, 0, url) + if (modules[url]) { + modules[url].state = 3 //loaded + var isCycle = false + try { + isCycle = checkCycle(modules[url].deps, url) + } catch (e) { + } + if (isCycle) { + avalon.error(url + "模å—与之å‰çš„模å—存在循环ä¾èµ–,请ä¸è¦ç›´æŽ¥ç”¨script标签引入" + url + "模å—") + } + } + delete factory.require //释放内存 + innerRequire.apply(null, args) //0,1,2 --> 1,2,0 + } +//æ ¹æ®æ ‡å‡†,所有éµå¾ªW3C标准的æµè§ˆå™¨,script标签会按标签的出现顺åºæ‰§è¡Œã€‚ +//è€çš„æµè§ˆå™¨ä¸­ï¼ŒåŠ è½½ä¹Ÿæ˜¯æŒ‰é¡ºåºçš„:一个文件下载完æˆåŽï¼Œæ‰å¼€å§‹ä¸‹è½½ä¸‹ä¸€ä¸ªæ–‡ä»¶ã€‚ +//较新的æµè§ˆå™¨ä¸­ï¼ˆIE8+ ã€FireFox3.5+ ã€Chrome4+ ã€Safari4+),为了å‡å°è¯·æ±‚时间以优化体验, +//下载å¯ä»¥æ˜¯å¹¶è¡Œçš„,但是执行顺åºè¿˜æ˜¯æŒ‰ç…§æ ‡ç­¾å‡ºçŽ°çš„顺åºã€‚ +//但如果script标签是动æ€æ’入的, 就未必按照先请求先执行的原则了,目测åªæœ‰firefoxéµå®ˆ +//唯一比较一致的是,IE10+åŠå…¶ä»–标准æµè§ˆå™¨,一旦开始解æžè„šæœ¬, 就会一直堵在那里,直接脚本解æžå®Œæ¯• +//亦å³ï¼Œå…ˆè¿›å…¥loading阶段的script标签(模å—)必然会先进入loaded阶段 + var url = config.built ? "unknown" : getCurrentScript() + if (url) { + var module = modules[url] + if (module) { + module.state = 2 + } + factory.require(url) + } else {//åˆå¹¶å‰åŽçš„safari,åˆå¹¶åŽçš„IE6-9走此分支 + factorys.push(factory) + } + } +//核心API之三 require.config(settings) + innerRequire.config = kernel + //核心API之四 define.amd 标识其符åˆAMD规范 + innerRequire.define.amd = modules + + //==========================对用户é…置项进行å†åŠ å·¥========================== + var allpaths = kernel["orig.paths"] = createMap() + var allmaps = kernel["orig.map"] = createMap() + var allpackages = kernel["packages"] = [] + var allargs = kernel["orig.args"] = createMap() + avalon.mix(plugins, { + paths: function (hash) { + avalon.mix(allpaths, hash) + kernel.paths = makeIndexArray(allpaths) + }, + map: function (hash) { + avalon.mix(allmaps, hash) + var list = makeIndexArray(allmaps, 1, 1) + avalon.each(list, function (_, item) { + item.val = makeIndexArray(item.val) + }) + kernel.map = list + }, + packages: function (array) { + array = array.concat(allpackages) + var uniq = createMap() + var ret = [] + for (var i = 0, pkg; pkg = array[i++];) { + pkg = typeof pkg === "string" ? {name: pkg} : pkg + var name = pkg.name + if (!uniq[name]) { + var url = joinPath(pkg.location || name, pkg.main || "main") + url = url.replace(rjsext, "") + ret.push(pkg) + uniq[name] = pkg.location = url + pkg.reg = makeMatcher(name) + } + } + kernel.packages = ret.sort() + }, + urlArgs: function (hash) { + if (typeof hash === "string") { + hash = {"*": hash} + } + avalon.mix(allargs, hash) + kernel.urlArgs = makeIndexArray(allargs, 1) + }, + baseUrl: function (url) { + if (!isAbsUrl(url)) { + var baseElement = head.getElementsByTagName("base")[0] + if (baseElement) { + head.removeChild(baseElement) + } + var node = DOC.createElement("a") + node.href = url + url = node.href + if (baseElement) { + head.insertBefore(baseElement, head.firstChild) + } + } + if (url.length > 3) + kernel.baseUrl = url + }, + shim: function (obj) { + for (var i in obj) { + var value = obj[i] + if (Array.isArray(value)) { + value = obj[i] = { + deps: value + } + } + if (!value.exportsFn && (value.exports || value.init)) { + value.exportsFn = makeExports(value) + } + } + kernel.shim = obj + } + + }) + + + //==============================内部方法================================= + function checkCycle(deps, nick) { + //检测是å¦å­˜åœ¨å¾ªçŽ¯ä¾èµ– + for (var i = 0, id; id = deps[i++];) { + if (modules[id].state !== 4 && + (id === nick || checkCycle(modules[id].deps, nick))) { + return true + } + } + } + + function checkFail(node, onError) { + var id = trimQuery(node.src) //检测是å¦æ­»é“¾ + node.onload = node.onerror = null + if (onError) { + setTimeout(function () { + head.removeChild(node) + node = null // 处ç†æ—§å¼IE下的循环引用问题 + }) + log("debug: 加载 " + id + " 失败" + onError + " " + (!modules[id].state)) + } else { + return true + } + } + + function checkDeps() { + //检测此JS模å—çš„ä¾èµ–是å¦éƒ½å·²å®‰è£…完毕,是则安装自身 + loop: for (var i = loadings.length, id; id = loadings[--i];) { + var obj = modules[id], + deps = obj.deps + if (!deps) + continue + for (var j = 0, key; key = deps[j]; j++) { + if (Object(modules[key]).state !== 4) { + continue loop + } + } + //如果deps是空对象或者其ä¾èµ–的模å—的状æ€éƒ½æ˜¯2 + if (obj.state !== 4) { + loadings.splice(i, 1) //必须先移除å†å®‰è£…,防止在IE下DOM树建完åŽæ‰‹åŠ¨åˆ·æ–°é¡µé¢ï¼Œä¼šå¤šæ¬¡æ‰§è¡Œå®ƒ + fireFactory(obj.id, obj.deps, obj.factory) + checkDeps() //如果æˆåŠŸ,则å†æ‰§è¡Œä¸€æ¬¡,以防有些模å—就差本模å—没有安装好 + } + } + } + + function loadJS(url, id, callback) { + //通过scriptèŠ‚ç‚¹åŠ è½½ç›®æ ‡æ¨¡å— + var node = DOC.createElement("script") + node.className = subscribers //让getCurrentScriptåªå¤„ç†ç±»å为subscribersçš„script节点 + node.onload = function () { + var factory = factorys.pop() + factory && factory.require(id) + if (callback) { + callback() + } + log("debug: å·²æˆåŠŸåŠ è½½ " + url) + id && loadings.push(id) + checkDeps() + } + node.onerror = function () { + checkFail(node, true) + } + + head.insertBefore(node, head.firstChild) //chrome下第二个å‚æ•°ä¸èƒ½ä¸ºnull + node.src = url //æ’入到head的第一个节点å‰ï¼Œé˜²æ­¢IE6下head标签没闭åˆå‰ä½¿ç”¨appendChild抛错 + log("debug: 正准备加载 " + url) //æ›´é‡è¦çš„是IE6下å¯ä»¥æ”¶çª„getCurrentScript的寻找范围 + } + + var resources = innerRequire.plugins = { + //三大常用资æºæ’件 js!, css!, text!, ready! + ready: { + load: noop + }, + js: { + load: function (name, req, onLoad) { + var url = req.url + var id = req.urlNoQuery + var shim = kernel.shim[name.replace(rjsext, "")] + if (shim) { //shim机制 + innerRequire(shim.deps || [], function () { + var args = avalon.slice(arguments) + loadJS(url, id, function () { + onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0) + }) + }) + } else { + loadJS(url, id) + } + } + }, + css: { + load: function (name, req, onLoad) { + var url = req.url + head.insertAdjacentHTML("afterBegin", '') + log("debug: å·²æˆåŠŸåŠ è½½ " + url) + onLoad() + } + }, + text: { + load: function (name, req, onLoad) { + var url = req.url + var xhr = getXHR() + xhr.onload = function () { + var status = xhr.status; + if (status > 399 && status < 600) { + avalon.error(url + " 对应资æºä¸å­˜åœ¨æˆ–æ²¡æœ‰å¼€å¯ CORS") + } else { + log("debug: å·²æˆåŠŸåŠ è½½ " + url) + onLoad(xhr.responseText) + } + } + xhr.open("GET", url, true) + if ("withCredentials" in xhr) {//这是处ç†è·¨åŸŸ + xhr.withCredentials = true + } + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")//告诉åŽç«¯è¿™æ˜¯AJAX请求 + xhr.send() + log("debug: 正准备加载 " + url) + } + } + } + innerRequire.checkDeps = checkDeps + + var rquery = /(\?[^#]*)$/ + + function trimQuery(url) { + return (url || "").replace(rquery, "") + } + + function isAbsUrl(path) { + //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative + return /^(?:[a-z]+:)?\/\//i.test(String(path)) + } + + + function getCurrentScript() { + // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js + var stack + try { + a.b.c() //强制报错,以便æ•èŽ·e.stack + } catch (e) { //safari5çš„sourceURL,firefoxçš„fileName,它们的效果与e.stackä¸ä¸€æ · + stack = e.stack + } + if (stack) { + /**e.stack最åŽä¸€è¡Œåœ¨æ‰€æœ‰æ”¯æŒçš„æµè§ˆå™¨å¤§è‡´å¦‚下: + *chrome23: + * at http://113.93.50.63/data.js:4:1 + *firefox17: + *@http://113.93.50.63/query.js:4 + *opera12:http://www.oldapps.com/opera.php?system=Windows_XP + *@http://113.93.50.63/data.js:4 + *IE10: + * at Global code (http://113.93.50.63/data.js:4:1) + * //firefox4+ å¯ä»¥ç”¨document.currentScript + */ + stack = stack.split(/[@ ]/g).pop() //å–得最åŽä¸€è¡Œ,最åŽä¸€ä¸ªç©ºæ ¼æˆ–@之åŽçš„部分 + stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉æ¢è¡Œç¬¦ + return trimQuery(stack.replace(/(:\d+)?:\d+$/i, "")) //去掉行å·ä¸Žæˆ–许存在的出错字符起始ä½ç½® + } + var nodes = head.getElementsByTagName("script") //åªåœ¨head标签中寻找 + for (var i = nodes.length, node; node = nodes[--i];) { + if (node.className === subscribers && node.readyState === "interactive") { + var url = node.src + return node.className = trimQuery(url) + } + } + } + + var rcallback = /^callback\d+$/ + + function fireFactory(id, deps, factory) { + var module = Object(modules[id]) + module.state = 4 + for (var i = 0, array = [], d; d = deps[i++];) { + if (d === "exports") { + var obj = module.exports || (module.exports = createMap()) + array.push(obj) + } else { + array.push(modules[d].exports) + } + } + try { + var ret = factory.apply(window, array) + } catch (e) { + log("执行[" + id + "]模å—çš„factory抛错: " + e) + } + if (ret !== void 0) { + module.exports = ret + } + if (rcallback.test(id)) { + delete modules[id] + } + delete module.factory + return ret + } + + function toUrl(id) { + if (id.indexOf(this.res + "!") === 0) { + id = id.slice(this.res.length + 1) //处ç†define("css!style",[], function(){})的情况 + } + var url = id + //1. 是å¦å‘½ä¸­pathsé…置项 + var usePath = 0 + var baseUrl = this.baseUrl + var rootUrl = this.parentUrl || baseUrl + eachIndexArray(id, kernel.paths, function (value, key) { + url = url.replace(key, value) + usePath = 1 + }) + //2. 是å¦å‘½ä¸­packagesé…置项 + if (!usePath) { + eachIndexArray(id, kernel.packages, function (value, key, item) { + url = url.replace(item.name, item.location) + }) + } + //3. 是å¦å‘½ä¸­mapé…置项 + if (this.mapUrl) { + eachIndexArray(this.mapUrl, kernel.map, function (array) { + eachIndexArray(url, array, function (mdValue, mdKey) { + url = url.replace(mdKey, mdValue) + rootUrl = baseUrl + }) + }) + } + var ext = this.ext + if (ext && usePath && url.slice(-ext.length) === ext) { + url = url.slice(0, -ext.length) + } + //4. 转æ¢ä¸ºç»å¯¹è·¯å¾„ + if (!isAbsUrl(url)) { + rootUrl = this.built || /^\w/.test(url) ? baseUrl : rootUrl + url = joinPath(rootUrl, url) + } + //5. 还原扩展å,query + var urlNoQuery = url + ext + url = urlNoQuery + this.query + //6. 处ç†urlArgs + eachIndexArray(id, kernel.urlArgs, function (value) { + url += (url.indexOf("?") === -1 ? "?" : "&") + value; + }) + this.url = url + return this.urlNoQuery = urlNoQuery + } + + function makeIndexArray(hash, useStar, part) { + //创建一个ç»è¿‡ç‰¹æ®Šç®—法排好åºçš„数组 + var index = hash2array(hash, useStar, part) + index.sort(descSorterByName) + return index + } + + function makeMatcher(prefix) { + return new RegExp('^' + prefix + '(/|$)') + } + + function makeExports(value) { + return function () { + var ret + if (value.init) { + ret = value.init.apply(window, arguments) + } + return ret || (value.exports && getGlobal(value.exports)) + } + } + + + function hash2array(hash, useStar, part) { + var array = []; + for (var key in hash) { + // if (hash.hasOwnProperty(key)) {//hash是由createMap创建没有hasOwnProperty + var item = { + name: key, + val: hash[key] + } + array.push(item) + item.reg = key === "*" && useStar ? /^/ : makeMatcher(key) + if (part && key !== "*") { + item.reg = new RegExp('\/' + key.replace(/^\//, "") + '(/|$)') + } + // } + } + return array + } + + function eachIndexArray(moduleID, array, matcher) { + array = array || [] + for (var i = 0, el; el = array[i++];) { + if (el.reg.test(moduleID)) { + matcher(el.val, el.name, el) + return false + } + } + } + + // æ ¹æ®å…ƒç´ çš„name项进行数组字符数逆åºçš„排åºå‡½æ•° + function descSorterByName(a, b) { + var aaa = a.name + var bbb = b.name + if (bbb === "*") { + return -1 + } + if (aaa === "*") { + return 1 + } + return bbb.length - aaa.length + } + + var rdeuce = /\/\w+\/\.\./ + + function joinPath(a, b) { + if (a.charAt(a.length - 1) !== "/") { + a += "/" + } + if (b.slice(0, 2) === "./") { //相对于兄弟路径 + return a + b.slice(2) + } + if (b.slice(0, 2) === "..") { //相对于父路径 + a += b + while (rdeuce.test(a)) { + a = a.replace(rdeuce, "") + } + return a + } + if (b.slice(0, 1) === "/") { + return a + b.slice(1) + } + return a + b + } + + function getGlobal(value) { + if (!value) { + return value + } + var g = window + value.split(".").forEach(function (part) { + g = g[part] + }) + return g + } + + var mainNode = DOC.scripts[DOC.scripts.length - 1] + var dataMain = mainNode.getAttribute("data-main") + if (dataMain) { + plugins.baseUrl(dataMain) + var href = kernel.baseUrl + kernel.baseUrl = href.slice(0, href.lastIndexOf("/") + 1) + loadJS(href.replace(rjsext, "") + ".js") + } else { + var loaderUrl = trimQuery(mainNode.src) + kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1) + } + }// jshint ignore:line + + /********************************************************************* + * DOMReady * + **********************************************************************/ + var readyList = [], isReady + var fireReady = function (fn) { + isReady = true + if (innerRequire) { + modules["domReady!"].state = 4 + innerRequire.checkDeps() + } + while (fn = readyList.shift()) { + fn(avalon) + } + } + + + if (DOC.readyState === "complete") { + setTimeout(fireReady) //如果在domReady之外加载 + } else { + DOC.addEventListener("DOMContentLoaded", fireReady) + } + window.addEventListener("load", fireReady) + avalon.ready = function (fn) { + if (!isReady) { + readyList.push(fn) + } else { + fn(avalon) + } + } + avalon.config({ + loader: true + }) + avalon.ready(function () { + avalon.scan(DOC.body) + }) + +// Register as a named AMD module, since avalon can be concatenated with other +// files that may use define, but not via a proper concatenation script that +// understands anonymous AMD modules. A named AMD is safest and most robust +// way to register. Lowercase avalon is used because AMD module names are +// derived from file names, and Avalon is normally delivered in a lowercase +// file name. Do this after creating the global so that if an AMD module wants +// to call noConflict to hide this version of avalon, it will work. + +// Note that for maximum portability, libraries that are not avalon should +// declare themselves as anonymous modules, and avoid setting a global if an +// AMD loader is present. avalon is a special case. For more information, see +// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon + if (typeof define === "function" && define.amd) { + define("avalon", [], function () { + return avalon + }) + } +// Map over avalon in case of overwrite + var _avalon = window.avalon + avalon.noConflict = function (deep) { + if (deep && window.avalon === avalon) { + window.avalon = _avalon + } + return avalon + } +// Expose avalon identifiers, even in AMD +// and CommonJS for browser emulators + if (noGlobal === void 0) { + window.avalon = avalon + } + + window._injectTer = function (code) { + return eval(code) + } + + return avalon + })); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/backstretch/jquery.backstretch.min.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/backstretch/jquery.backstretch.min.js index 874c1a6c..4b14f7ab 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/backstretch/jquery.backstretch.min.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/backstretch/jquery.backstretch.min.js @@ -1,4 +1,4 @@ -/*! Backstretch - v2.0.3 - 2012-11-30 -* http://srobbin.com/jquery-plugins/backstretch/ -* Copyright (c) 2012 Scott Robbin; Licensed MIT */ +/*! Backstretch - v2.0.3 - 2012-11-30 +* http://srobbin.com/jquery-plugins/backstretch/ +* Copyright (c) 2012 Scott Robbin; Licensed MIT */ (function(e,t,n){"use strict";e.fn.backstretch=function(r,s){return(r===n||r.length===0)&&e.error("No images were supplied for Backstretch"),e(t).scrollTop()===0&&t.scrollTo(0,0),this.each(function(){var t=e(this),n=t.data("backstretch");n&&(s=e.extend(n.options,s),n.destroy(!0)),n=new i(this,r,s),t.data("backstretch",n)})},e.backstretch=function(t,n){return e("body").backstretch(t,n).data("backstretch")},e.expr[":"].backstretch=function(t){return e(t).data("backstretch")!==n},e.fn.backstretch.defaults={centeredX:!0,centeredY:!0,duration:5e3,fade:0};var r={wrap:{left:0,top:0,overflow:"hidden",margin:0,padding:0,height:"100%",width:"100%",zIndex:-999999},img:{position:"absolute",display:"none",margin:0,padding:0,border:"none",width:"auto",height:"auto",maxWidth:"none",zIndex:-999999}},i=function(n,i,o){this.options=e.extend({},e.fn.backstretch.defaults,o||{}),this.images=e.isArray(i)?i:[i],e.each(this.images,function(){e("")[0].src=this}),this.isBody=n===document.body,this.$container=e(n),this.$wrap=e('
').css(r.wrap).appendTo(this.$container),this.$root=this.isBody?s?e(t):e(document):this.$container;if(!this.isBody){var u=this.$container.css("position"),a=this.$container.css("zIndex");this.$container.css({position:u==="static"?"relative":u,zIndex:a==="auto"?0:a,background:"none"}),this.$wrap.css({zIndex:-999998})}this.$wrap.css({position:this.isBody&&s?"fixed":"absolute"}),this.index=0,this.show(this.index),e(t).on("resize.backstretch",e.proxy(this.resize,this)).on("orientationchange.backstretch",e.proxy(function(){this.isBody&&t.pageYOffset===0&&(t.scrollTo(0,1),this.resize())},this))};i.prototype={resize:function(){try{var e={left:0,top:0},n=this.isBody?this.$root.width():this.$root.innerWidth(),r=n,i=this.isBody?t.innerHeight?t.innerHeight:this.$root.height():this.$root.innerHeight(),s=r/this.$img.data("ratio"),o;s>=i?(o=(s-i)/2,this.options.centeredY&&(e.top="-"+o+"px")):(s=i,r=s*this.$img.data("ratio"),o=(r-n)/2,this.options.centeredX&&(e.left="-"+o+"px")),this.$wrap.css({width:n,height:i}).find("img:not(.deleteable)").css({width:r,height:s}).css(e)}catch(u){}return this},show:function(t){if(Math.abs(t)>this.images.length-1)return;this.index=t;var n=this,i=n.$wrap.find("img").addClass("deleteable"),s=e.Event("backstretch.show",{relatedTarget:n.$container[0]});return clearInterval(n.interval),n.$img=e("").css(r.img).bind("load",function(t){var r=this.width||e(t.target).width(),o=this.height||e(t.target).height();e(this).data("ratio",r/o),e(this).fadeIn(n.options.speed||n.options.fade,function(){i.remove(),n.paused||n.cycle(),n.$container.trigger(s,n)}),n.resize()}).appendTo(n.$wrap),n.$img.attr("src",n.images[t]),n},next:function(){return this.show(this.index1&&(clearInterval(this.interval),this.interval=setInterval(e.proxy(function(){this.paused||this.next()},this),this.options.duration)),this},destroy:function(n){e(t).off("resize.backstretch orientationchange.backstretch"),clearInterval(this.interval),n||this.$wrap.remove(),this.$container.removeData("backstretch")}};var s=function(){var e=navigator.userAgent,n=navigator.platform,r=e.match(/AppleWebKit\/([0-9]+)/),i=!!r&&r[1],s=e.match(/Fennec\/([0-9]+)/),o=!!s&&s[1],u=e.match(/Opera Mobi\/([0-9]+)/),a=!!u&&u[1],f=e.match(/MSIE ([0-9]+)/),l=!!f&&f[1];return!((n.indexOf("iPhone")>-1||n.indexOf("iPad")>-1||n.indexOf("iPod")>-1)&&i&&i<534||t.operamini&&{}.toString.call(t.operamini)==="[object OperaMini]"||u&&a<7458||e.indexOf("Android")>-1&&i&&i<533||o&&o<6||"palmGetResource"in t&&i&&i<534||e.indexOf("MeeGo")>-1&&e.indexOf("NokiaBrowser/8.5.0")>-1||l&&l<=6)}()})(jQuery,window); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/LICENSE.md b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/LICENSE.md index 8219f598..4c723486 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/LICENSE.md +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/LICENSE.md @@ -1,23 +1,23 @@ -# License - -(The MIT License) - -Copyright (C) 2011-2014 by Nick Payne - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE +# License + +(The MIT License) + +Copyright (C) 2011-2014 by Nick Payne + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/README.md b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/README.md index eedb7210..700fd6f7 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/README.md +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/README.md @@ -1,91 +1,91 @@ -# Bootbox - Bootstrap powered alert, confirm and flexible dialog boxes - -Please see http://bootboxjs.com for full usage instructions, or head over to http://paynedigital.com/bootbox for -the original writeup about the project. - -## Contact - -The easiest thing is to [find me on twitter @makeusabrew](http://twitter.com/makeusabrew). - -## Contributing - -Please see the [CONTRIBUTING](https://github.com/makeusabrew/bootbox/blob/master/CONTRIBUTING.md) file for guidelines. - -## Running Tests [![Build Status](https://api.travis-ci.org/makeusabrew/bootbox.svg)](http://travis-ci.org/makeusabrew/bootbox) - -Tests are run using [Karma](http://karma-runner.github.io/0.8/index.html) using the Mocha test adapter. -To run the tests yourself, simply run ```npm install``` within the project followed by ```npm test```. -Please note that this will require [PhantomJS](http://phantomjs.org/) being installed and in your path - if -it is not, you may run the tests and capture browsers manually by running ```karma start``` from the root -of the project. - -The project is also hosted on [Travis CI](https://travis-ci.org/makeusabrew/bootbox) - when submitting -pull requests **please** ensure your tests pass as failing requests will be rejected. See the -[CONTRIBUTING](https://github.com/makeusabrew/bootbox/blob/master/CONTRIBUTING.md) file for more information. - -## Building a minified release - -The repository no longer contains a minified bootbox.min.js file - this is now only generated -[for releases](https://github.com/makeusabrew/bootbox/releases). To build your own minified copy -for use in development simply run ```npm install``` if you haven't already, followed by ```grunt uglify```. -This will generate a bootbox.min.js file in your working directory. - -## A note on Bootstrap dependencies - -Bootbox **4.0.0** is the first release to support Bootstrap 3.0.0. - -Bootbox **3.3.0** is the *last* release to support Bootstrap 2.2.x. - -Much more dependency information can be found [on the Bootbox website](http://bootboxjs.com/#dependencies). - -### Roadmap - -The latest major release of Bootbox - 4.0.0 - involved a total rewrite of the -internal code and introduced an entirely new public API. It has not re-implemented -some functionality from the 3.x series as of yet; this will be addressed in the -coming weeks in the form of new minor releases; -[a task list for 4.3.0 is available](https://github.com/makeusabrew/bootbox/issues/220) - -please feel free to add feedback and requests. - -There is no new major (e.g. 5.x) release on the roadmap at present. - -## Latest Release: 4.2.0 - -* Add Swedish locale -* Add Latvian locale -* Add Turkish locale -* Add Hebrew locale -* Add password input type -* Add textarea input type -* Add date input type -* Add time input type -* Add number input type -* Support DOM selectors for container argument -* UMD support -* Better support on mobile devices - -For a full list of releases and changes please see [the changelog](https://github.com/makeusabrew/bootbox/blob/master/CHANGELOG.md). - -## License - -(The MIT License) - -Copyright (C) 2011-2014 by Nick Payne - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE +# Bootbox - Bootstrap powered alert, confirm and flexible dialog boxes + +Please see http://bootboxjs.com for full usage instructions, or head over to http://paynedigital.com/bootbox for +the original writeup about the project. + +## Contact + +The easiest thing is to [find me on twitter @makeusabrew](http://twitter.com/makeusabrew). + +## Contributing + +Please see the [CONTRIBUTING](https://github.com/makeusabrew/bootbox/blob/master/CONTRIBUTING.md) file for guidelines. + +## Running Tests [![Build Status](https://api.travis-ci.org/makeusabrew/bootbox.svg)](http://travis-ci.org/makeusabrew/bootbox) + +Tests are run using [Karma](http://karma-runner.github.io/0.8/index.html) using the Mocha test adapter. +To run the tests yourself, simply run ```npm install``` within the project followed by ```npm test```. +Please note that this will require [PhantomJS](http://phantomjs.org/) being installed and in your path - if +it is not, you may run the tests and capture browsers manually by running ```karma start``` from the root +of the project. + +The project is also hosted on [Travis CI](https://travis-ci.org/makeusabrew/bootbox) - when submitting +pull requests **please** ensure your tests pass as failing requests will be rejected. See the +[CONTRIBUTING](https://github.com/makeusabrew/bootbox/blob/master/CONTRIBUTING.md) file for more information. + +## Building a minified release + +The repository no longer contains a minified bootbox.min.js file - this is now only generated +[for releases](https://github.com/makeusabrew/bootbox/releases). To build your own minified copy +for use in development simply run ```npm install``` if you haven't already, followed by ```grunt uglify```. +This will generate a bootbox.min.js file in your working directory. + +## A note on Bootstrap dependencies + +Bootbox **4.0.0** is the first release to support Bootstrap 3.0.0. + +Bootbox **3.3.0** is the *last* release to support Bootstrap 2.2.x. + +Much more dependency information can be found [on the Bootbox website](http://bootboxjs.com/#dependencies). + +### Roadmap + +The latest major release of Bootbox - 4.0.0 - involved a total rewrite of the +internal code and introduced an entirely new public API. It has not re-implemented +some functionality from the 3.x series as of yet; this will be addressed in the +coming weeks in the form of new minor releases; +[a task list for 4.3.0 is available](https://github.com/makeusabrew/bootbox/issues/220) - +please feel free to add feedback and requests. + +There is no new major (e.g. 5.x) release on the roadmap at present. + +## Latest Release: 4.2.0 + +* Add Swedish locale +* Add Latvian locale +* Add Turkish locale +* Add Hebrew locale +* Add password input type +* Add textarea input type +* Add date input type +* Add time input type +* Add number input type +* Support DOM selectors for container argument +* UMD support +* Better support on mobile devices + +For a full list of releases and changes please see [the changelog](https://github.com/makeusabrew/bootbox/blob/master/CHANGELOG.md). + +## License + +(The MIT License) + +Copyright (C) 2011-2014 by Nick Payne + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/bootbox.min.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/bootbox.min.js index a7ea24fe..a5d01a50 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/bootbox.min.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootbox/bootbox.min.js @@ -1,6 +1,6 @@ -/** - * bootbox.js v4.3.0 - * - * http://bootboxjs.com/license.txt - */ +/** + * bootbox.js v4.3.0 + * + * http://bootboxjs.com/license.txt + */ !function(a,b){"use strict";"function"==typeof define&&define.amd?define(["jquery"],b):"object"==typeof exports?module.exports=b(require("jquery")):a.bootbox=b(a.jQuery)}(this,function a(b,c){"use strict";function d(a){var b=q[o.locale];return b?b[a]:q.en[a]}function e(a,c,d){a.stopPropagation(),a.preventDefault();var e=b.isFunction(d)&&d(a)===!1;e||c.modal("hide")}function f(a){var b,c=0;for(b in a)c++;return c}function g(a,c){var d=0;b.each(a,function(a,b){c(a,b,d++)})}function h(a){var c,d;if("object"!=typeof a)throw new Error("Please supply an object of options");if(!a.message)throw new Error("Please specify a message");return a=b.extend({},o,a),a.buttons||(a.buttons={}),a.backdrop=a.backdrop?"static":!1,c=a.buttons,d=f(c),g(c,function(a,e,f){if(b.isFunction(e)&&(e=c[a]={callback:e}),"object"!==b.type(e))throw new Error("button with key "+a+" must be an object");e.label||(e.label=a),e.className||(e.className=2>=d&&f===d-1?"btn-primary":"btn-default")}),a}function i(a,b){var c=a.length,d={};if(1>c||c>2)throw new Error("Invalid argument length");return 2===c||"string"==typeof a[0]?(d[b[0]]=a[0],d[b[1]]=a[1]):d=a[0],d}function j(a,c,d){return b.extend(!0,{},a,i(c,d))}function k(a,b,c,d){var e={className:"bootbox-"+a,buttons:l.apply(null,b)};return m(j(e,d,c),b)}function l(){for(var a={},b=0,c=arguments.length;c>b;b++){var e=arguments[b],f=e.toLowerCase(),g=e.toUpperCase();a[f]={label:d(g)}}return a}function m(a,b){var d={};return g(b,function(a,b){d[b]=!0}),g(a.buttons,function(a){if(d[a]===c)throw new Error("button key "+a+" is not allowed (options are "+b.join("\n")+")")}),a}var n={dialog:"",header:"",footer:"",closeButton:"",form:"
",inputs:{text:"",textarea:"",email:"",select:"",checkbox:"
",date:"",time:"",number:"",password:""}},o={locale:"en",backdrop:!0,animate:!0,className:null,closeButton:!0,show:!0,container:"body"},p={};p.alert=function(){var a;if(a=k("alert",["ok"],["message","callback"],arguments),a.callback&&!b.isFunction(a.callback))throw new Error("alert requires callback property to be a function when provided");return a.buttons.ok.callback=a.onEscape=function(){return b.isFunction(a.callback)?a.callback():!0},p.dialog(a)},p.confirm=function(){var a;if(a=k("confirm",["cancel","confirm"],["message","callback"],arguments),a.buttons.cancel.callback=a.onEscape=function(){return a.callback(!1)},a.buttons.confirm.callback=function(){return a.callback(!0)},!b.isFunction(a.callback))throw new Error("confirm requires a callback");return p.dialog(a)},p.prompt=function(){var a,d,e,f,h,i,k;if(f=b(n.form),d={className:"bootbox-prompt",buttons:l("cancel","confirm"),value:"",inputType:"text"},a=m(j(d,arguments,["title","callback"]),["cancel","confirm"]),i=a.show===c?!0:a.show,a.message=f,a.buttons.cancel.callback=a.onEscape=function(){return a.callback(null)},a.buttons.confirm.callback=function(){var c;switch(a.inputType){case"text":case"textarea":case"email":case"select":case"date":case"time":case"number":case"password":c=h.val();break;case"checkbox":var d=h.find("input:checked");c=[],g(d,function(a,d){c.push(b(d).val())})}return a.callback(c)},a.show=!1,!a.title)throw new Error("prompt requires a title");if(!b.isFunction(a.callback))throw new Error("prompt requires a callback");if(!n.inputs[a.inputType])throw new Error("invalid prompt type");switch(h=b(n.inputs[a.inputType]),a.inputType){case"text":case"textarea":case"email":case"date":case"time":case"number":case"password":h.val(a.value);break;case"select":var o={};if(k=a.inputOptions||[],!k.length)throw new Error("prompt with select requires options");g(k,function(a,d){var e=h;if(d.value===c||d.text===c)throw new Error("given options in wrong format");d.group&&(o[d.group]||(o[d.group]=b("").attr("label",d.group)),e=o[d.group]),e.append("")}),g(o,function(a,b){h.append(b)}),h.val(a.value);break;case"checkbox":var q=b.isArray(a.value)?a.value:[a.value];if(k=a.inputOptions||[],!k.length)throw new Error("prompt with checkbox requires options");if(!k[0].value||!k[0].text)throw new Error("given options in wrong format");h=b("
"),g(k,function(c,d){var e=b(n.inputs[a.inputType]);e.find("input").attr("value",d.value),e.find("label").append(d.text),g(q,function(a,b){b===d.value&&e.find("input").prop("checked",!0)}),h.append(e)})}return a.placeholder&&h.attr("placeholder",a.placeholder),a.pattern&&h.attr("pattern",a.pattern),f.append(h),f.on("submit",function(a){a.preventDefault(),a.stopPropagation(),e.find(".btn-primary").click()}),e=p.dialog(a),e.off("shown.bs.modal"),e.on("shown.bs.modal",function(){h.focus()}),i===!0&&e.modal("show"),e},p.dialog=function(a){a=h(a);var c=b(n.dialog),d=c.find(".modal-dialog"),f=c.find(".modal-body"),i=a.buttons,j="",k={onEscape:a.onEscape};if(g(i,function(a,b){j+="",k[a]=b.callback}),f.find(".bootbox-body").html(a.message),a.animate===!0&&c.addClass("fade"),a.className&&c.addClass(a.className),"large"===a.size&&d.addClass("modal-lg"),"small"===a.size&&d.addClass("modal-sm"),a.title&&f.before(n.header),a.closeButton){var l=b(n.closeButton);a.title?c.find(".modal-header").prepend(l):l.css("margin-top","-10px").prependTo(f)}return a.title&&c.find(".modal-title").html(a.title),j.length&&(f.after(n.footer),c.find(".modal-footer").html(j)),c.on("hidden.bs.modal",function(a){a.target===this&&c.remove()}),c.on("shown.bs.modal",function(){c.find(".btn-primary:first").focus()}),c.on("escape.close.bb",function(a){k.onEscape&&e(a,c,k.onEscape)}),c.on("click",".modal-footer button",function(a){var d=b(this).data("bb-handler");e(a,c,k[d])}),c.on("click",".bootbox-close-button",function(a){e(a,c,k.onEscape)}),c.on("keyup",function(a){27===a.which&&c.trigger("escape.close.bb")}),b(a.container).append(c),c.modal({backdrop:a.backdrop,keyboard:!1,show:!1}),a.show&&c.modal("show"),c},p.setDefaults=function(){var a={};2===arguments.length?a[arguments[0]]=arguments[1]:a=arguments[0],b.extend(o,a)},p.hideAll=function(){return b(".bootbox").modal("hide"),p};var q={br:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Sim"},cs:{OK:"OK",CANCEL:"ZruÅ¡it",CONFIRM:"Potvrdit"},da:{OK:"OK",CANCEL:"Annuller",CONFIRM:"Accepter"},de:{OK:"OK",CANCEL:"Abbrechen",CONFIRM:"Akzeptieren"},el:{OK:"Εντάξει",CANCEL:"ΑκÏÏωση",CONFIRM:"Επιβεβαίωση"},en:{OK:"OK",CANCEL:"Cancel",CONFIRM:"OK"},es:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Aceptar"},et:{OK:"OK",CANCEL:"Katkesta",CONFIRM:"OK"},fi:{OK:"OK",CANCEL:"Peruuta",CONFIRM:"OK"},fr:{OK:"OK",CANCEL:"Annuler",CONFIRM:"D'accord"},he:{OK:"×ישור",CANCEL:"ביטול",CONFIRM:"×ישור"},id:{OK:"OK",CANCEL:"Batal",CONFIRM:"OK"},it:{OK:"OK",CANCEL:"Annulla",CONFIRM:"Conferma"},ja:{OK:"OK",CANCEL:"キャンセル",CONFIRM:"確èª"},lt:{OK:"Gerai",CANCEL:"AtÅ¡aukti",CONFIRM:"Patvirtinti"},lv:{OK:"Labi",CANCEL:"Atcelt",CONFIRM:"ApstiprinÄt"},nl:{OK:"OK",CANCEL:"Annuleren",CONFIRM:"Accepteren"},no:{OK:"OK",CANCEL:"Avbryt",CONFIRM:"OK"},pl:{OK:"OK",CANCEL:"Anuluj",CONFIRM:"Potwierdź"},pt:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Confirmar"},ru:{OK:"OK",CANCEL:"Отмена",CONFIRM:"Применить"},sv:{OK:"OK",CANCEL:"Avbryt",CONFIRM:"OK"},tr:{OK:"Tamam",CANCEL:"Ä°ptal",CONFIRM:"Onayla"},zh_CN:{OK:"OK",CANCEL:"å–消",CONFIRM:"确认"},zh_TW:{OK:"OK",CANCEL:"å–消",CONFIRM:"確èª"}};return p.init=function(c){return a(c||b)},p}); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/daterangepicker-bs3.css b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/daterangepicker-bs3.css index 71111cf7..8df7b075 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/daterangepicker-bs3.css +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/daterangepicker-bs3.css @@ -1,319 +1,319 @@ -/*! - * Stylesheet for the Date Range Picker, for use with Bootstrap 3.x - * - * Copyright 2013-2015 Dan Grossman ( http://www.dangrossman.info ) - * Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php - * - * Built for http://www.improvely.com - */ - - .daterangepicker.dropdown-menu { - max-width: none; - z-index: 3000; -} - -.daterangepicker.opensleft .ranges, .daterangepicker.opensleft .calendar { - float: left; - margin: 4px; -} - -.daterangepicker.opensright .ranges, .daterangepicker.opensright .calendar, -.daterangepicker.openscenter .ranges, .daterangepicker.openscenter .calendar { - float: right; - margin: 4px; -} - -.daterangepicker.single .ranges, .daterangepicker.single .calendar { - float: none; -} - -.daterangepicker .ranges { - width: 165px; - text-align: left; -} - -.daterangepicker .ranges .range_inputs>div { - float: left; -} - -.daterangepicker .ranges .range_inputs>div:nth-child(2) { - padding-left: 11px; -} - -.daterangepicker .calendar { - display: none; - max-width: 270px; -} - -.daterangepicker.show-calendar .calendar { - display: block; -} - -.daterangepicker .calendar.single .calendar-date { - border: none; -} - -.daterangepicker .calendar th, .daterangepicker .calendar td { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; - white-space: nowrap; - text-align: center; - min-width: 32px; -} - -.daterangepicker .daterangepicker_start_input label, -.daterangepicker .daterangepicker_end_input label { - color: #333; - display: block; - font-size: 11px; - font-weight: normal; - height: 20px; - line-height: 20px; - margin-bottom: 2px; - text-shadow: #fff 1px 1px 0px; - text-transform: uppercase; - width: 74px; -} - -.daterangepicker .ranges input { - font-size: 11px; -} - -.daterangepicker .ranges .input-mini { - border: 1px solid #ccc; - border-radius: 4px; - color: #555; - display: block; - font-size: 11px; - height: 30px; - line-height: 30px; - vertical-align: middle; - margin: 0 0 10px 0; - padding: 0 6px; - width: 77px; -} - -.daterangepicker .ranges ul { - list-style: none; - margin: 0; - padding: 0; -} - -.daterangepicker .ranges li { - font-size: 13px; - background: #f5f5f5; - border: 1px solid #f5f5f5; - color: #08c; - padding: 3px 12px; - margin-bottom: 8px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - cursor: pointer; -} - -.daterangepicker .ranges li.active, .daterangepicker .ranges li:hover { - background: #08c; - border: 1px solid #08c; - color: #fff; -} - -.daterangepicker .calendar-date { - border: 1px solid #ddd; - padding: 4px; - border-radius: 4px; - background: #fff; -} - -.daterangepicker .calendar-time { - text-align: center; - margin: 8px auto 0 auto; - line-height: 30px; -} - -.daterangepicker { - position: absolute; - background: #fff; - top: 100px; - left: 20px; - padding: 4px; - margin-top: 1px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.daterangepicker.opensleft:before { - position: absolute; - top: -7px; - right: 9px; - display: inline-block; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-left: 7px solid transparent; - border-bottom-color: rgba(0, 0, 0, 0.2); - content: ''; -} - -.daterangepicker.opensleft:after { - position: absolute; - top: -6px; - right: 10px; - display: inline-block; - border-right: 6px solid transparent; - border-bottom: 6px solid #fff; - border-left: 6px solid transparent; - content: ''; -} - -.daterangepicker.openscenter:before { - position: absolute; - top: -7px; - left: 0; - right: 0; - width: 0; - margin-left: auto; - margin-right: auto; - display: inline-block; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-left: 7px solid transparent; - border-bottom-color: rgba(0, 0, 0, 0.2); - content: ''; -} - -.daterangepicker.openscenter:after { - position: absolute; - top: -6px; - left: 0; - right: 0; - width: 0; - margin-left: auto; - margin-right: auto; - display: inline-block; - border-right: 6px solid transparent; - border-bottom: 6px solid #fff; - border-left: 6px solid transparent; - content: ''; -} - -.daterangepicker.opensright:before { - position: absolute; - top: -7px; - left: 9px; - display: inline-block; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-left: 7px solid transparent; - border-bottom-color: rgba(0, 0, 0, 0.2); - content: ''; -} - -.daterangepicker.opensright:after { - position: absolute; - top: -6px; - left: 10px; - display: inline-block; - border-right: 6px solid transparent; - border-bottom: 6px solid #fff; - border-left: 6px solid transparent; - content: ''; -} - -.daterangepicker table { - width: 100%; - margin: 0; -} - -.daterangepicker td, .daterangepicker th { - text-align: center; - width: 20px; - height: 20px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - cursor: pointer; - white-space: nowrap; -} - -.daterangepicker td.off { - color: #999; -} - -.daterangepicker td.disabled, .daterangepicker option.disabled { - color: #999; -} - -.daterangepicker td.available:hover, .daterangepicker th.available:hover { - background: #eee; -} - -.daterangepicker td.in-range { - background: #ebf4f8; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.daterangepicker td.start-date { - -webkit-border-radius: 4px 0 0 4px; - -moz-border-radius: 4px 0 0 4px; - border-radius: 4px 0 0 4px; -} - -.daterangepicker td.end-date { - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; -} - -.daterangepicker td.start-date.end-date { - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.daterangepicker td.active, .daterangepicker td.active:hover { - background-color: #357ebd; - border-color: #3071a9; - color: #fff; -} - -.daterangepicker td.week, .daterangepicker th.week { - font-size: 80%; - color: #ccc; -} - -.daterangepicker select.monthselect, .daterangepicker select.yearselect { - font-size: 12px; - padding: 1px; - height: auto; - margin: 0; - cursor: default; -} - -.daterangepicker select.monthselect { - margin-right: 2%; - width: 56%; -} - -.daterangepicker select.yearselect { - width: 40%; -} - -.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect { - width: 50px; - margin-bottom: 0; -} - -.daterangepicker_start_input { - float: left; -} - -.daterangepicker_end_input { - float: left; - padding-left: 11px -} - -.daterangepicker th.month { - width: auto; -} +/*! + * Stylesheet for the Date Range Picker, for use with Bootstrap 3.x + * + * Copyright 2013-2015 Dan Grossman ( http://www.dangrossman.info ) + * Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php + * + * Built for http://www.improvely.com + */ + + .daterangepicker.dropdown-menu { + max-width: none; + z-index: 3000; +} + +.daterangepicker.opensleft .ranges, .daterangepicker.opensleft .calendar { + float: left; + margin: 4px; +} + +.daterangepicker.opensright .ranges, .daterangepicker.opensright .calendar, +.daterangepicker.openscenter .ranges, .daterangepicker.openscenter .calendar { + float: right; + margin: 4px; +} + +.daterangepicker.single .ranges, .daterangepicker.single .calendar { + float: none; +} + +.daterangepicker .ranges { + width: 165px; + text-align: left; +} + +.daterangepicker .ranges .range_inputs>div { + float: left; +} + +.daterangepicker .ranges .range_inputs>div:nth-child(2) { + padding-left: 11px; +} + +.daterangepicker .calendar { + display: none; + max-width: 270px; +} + +.daterangepicker.show-calendar .calendar { + display: block; +} + +.daterangepicker .calendar.single .calendar-date { + border: none; +} + +.daterangepicker .calendar th, .daterangepicker .calendar td { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + white-space: nowrap; + text-align: center; + min-width: 32px; +} + +.daterangepicker .daterangepicker_start_input label, +.daterangepicker .daterangepicker_end_input label { + color: #333; + display: block; + font-size: 11px; + font-weight: normal; + height: 20px; + line-height: 20px; + margin-bottom: 2px; + text-shadow: #fff 1px 1px 0px; + text-transform: uppercase; + width: 74px; +} + +.daterangepicker .ranges input { + font-size: 11px; +} + +.daterangepicker .ranges .input-mini { + border: 1px solid #ccc; + border-radius: 4px; + color: #555; + display: block; + font-size: 11px; + height: 30px; + line-height: 30px; + vertical-align: middle; + margin: 0 0 10px 0; + padding: 0 6px; + width: 77px; +} + +.daterangepicker .ranges ul { + list-style: none; + margin: 0; + padding: 0; +} + +.daterangepicker .ranges li { + font-size: 13px; + background: #f5f5f5; + border: 1px solid #f5f5f5; + color: #08c; + padding: 3px 12px; + margin-bottom: 8px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + cursor: pointer; +} + +.daterangepicker .ranges li.active, .daterangepicker .ranges li:hover { + background: #08c; + border: 1px solid #08c; + color: #fff; +} + +.daterangepicker .calendar-date { + border: 1px solid #ddd; + padding: 4px; + border-radius: 4px; + background: #fff; +} + +.daterangepicker .calendar-time { + text-align: center; + margin: 8px auto 0 auto; + line-height: 30px; +} + +.daterangepicker { + position: absolute; + background: #fff; + top: 100px; + left: 20px; + padding: 4px; + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.daterangepicker.opensleft:before { + position: absolute; + top: -7px; + right: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.daterangepicker.opensleft:after { + position: absolute; + top: -6px; + right: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; + content: ''; +} + +.daterangepicker.openscenter:before { + position: absolute; + top: -7px; + left: 0; + right: 0; + width: 0; + margin-left: auto; + margin-right: auto; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.daterangepicker.openscenter:after { + position: absolute; + top: -6px; + left: 0; + right: 0; + width: 0; + margin-left: auto; + margin-right: auto; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; + content: ''; +} + +.daterangepicker.opensright:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.daterangepicker.opensright:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; + content: ''; +} + +.daterangepicker table { + width: 100%; + margin: 0; +} + +.daterangepicker td, .daterangepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + cursor: pointer; + white-space: nowrap; +} + +.daterangepicker td.off { + color: #999; +} + +.daterangepicker td.disabled, .daterangepicker option.disabled { + color: #999; +} + +.daterangepicker td.available:hover, .daterangepicker th.available:hover { + background: #eee; +} + +.daterangepicker td.in-range { + background: #ebf4f8; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.daterangepicker td.start-date { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.daterangepicker td.end-date { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.daterangepicker td.start-date.end-date { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.daterangepicker td.active, .daterangepicker td.active:hover { + background-color: #357ebd; + border-color: #3071a9; + color: #fff; +} + +.daterangepicker td.week, .daterangepicker th.week { + font-size: 80%; + color: #ccc; +} + +.daterangepicker select.monthselect, .daterangepicker select.yearselect { + font-size: 12px; + padding: 1px; + height: auto; + margin: 0; + cursor: default; +} + +.daterangepicker select.monthselect { + margin-right: 2%; + width: 56%; +} + +.daterangepicker select.yearselect { + width: 40%; +} + +.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect { + width: 50px; + margin-bottom: 0; +} + +.daterangepicker_start_input { + float: left; +} + +.daterangepicker_end_input { + float: left; + padding-left: 11px +} + +.daterangepicker th.month { + width: auto; +} diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/daterangepicker.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/daterangepicker.js index c24c0ad6..e2bc86d7 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/daterangepicker.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/daterangepicker.js @@ -1,1257 +1,1257 @@ -/** -* @version: 1.3.17 -* @author: Dan Grossman http://www.dangrossman.info/ -* @date: 2014-11-25 -* @copyright: Copyright (c) 2012-2014 Dan Grossman. All rights reserved. -* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php -* @website: http://www.improvely.com/ -*/ - -(function(root, factory) { - - if (typeof define === 'function' && define.amd) { - define(['moment', 'jquery', 'exports'], function(momentjs, $, exports) { - root.daterangepicker = factory(root, exports, momentjs, $); - }); - - } else if (typeof exports !== 'undefined') { - var momentjs = require('moment'); - var jQuery; - try { - jQuery = require('jquery'); - } catch (err) { - jQuery = window.jQuery; - if (!jQuery) throw new Error('jQuery dependency not found'); - } - - factory(root, exports, momentjs, jQuery); - - // Finally, as a browser global. - } else { - root.daterangepicker = factory(root, {}, root.moment, (root.jQuery || root.Zepto || root.ender || root.$)); - } - -}(this, function(root, daterangepicker, moment, $) { - - var DateRangePicker = function (element, options, cb) { - - // by default, the daterangepicker element is placed at the bottom of HTML body - this.parentEl = 'body'; - - //element that triggered the date range picker - this.element = $(element); - - //tracks visible state - this.isShowing = false; - - //create the picker HTML object - var DRPTemplate = ''; - - //custom options - if (typeof options !== 'object' || options === null) - options = {}; - - this.parentEl = (typeof options === 'object' && options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl); - this.container = $(DRPTemplate).appendTo(this.parentEl); - - this.setOptions(options, cb); - - //apply CSS classes and labels to buttons - var c = this.container; - $.each(this.buttonClasses, function (idx, val) { - c.find('button').addClass(val); - }); - this.container.find('.daterangepicker_start_input label').html(this.locale.fromLabel); - this.container.find('.daterangepicker_end_input label').html(this.locale.toLabel); - if (this.applyClass.length) - this.container.find('.applyBtn').addClass(this.applyClass); - if (this.cancelClass.length) - this.container.find('.cancelBtn').addClass(this.cancelClass); - this.container.find('.applyBtn').html(this.locale.applyLabel); - this.container.find('.cancelBtn').html(this.locale.cancelLabel); - - //event listeners - - this.container.find('.calendar') - .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this)) - .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this)) - .on('click.daterangepicker', 'td.available', $.proxy(this.clickDate, this)) - .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this)) - .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this)) - .on('change.daterangepicker', 'select.yearselect', $.proxy(this.updateMonthYear, this)) - .on('change.daterangepicker', 'select.monthselect', $.proxy(this.updateMonthYear, this)) - .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.updateTime, this)); - - this.container.find('.ranges') - .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this)) - .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this)) - .on('click.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.showCalendars, this)) - .on('change.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.inputsChanged, this)) - .on('keydown.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.inputsKeydown, this)) - .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this)) - .on('mouseenter.daterangepicker', 'li', $.proxy(this.enterRange, this)) - .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this)); - - if (this.element.is('input')) { - this.element.on({ - 'click.daterangepicker': $.proxy(this.show, this), - 'focus.daterangepicker': $.proxy(this.show, this), - 'keyup.daterangepicker': $.proxy(this.updateFromControl, this) - }); - } else { - this.element.on('click.daterangepicker', $.proxy(this.toggle, this)); - } - - }; - - DateRangePicker.prototype = { - - constructor: DateRangePicker, - - setOptions: function(options, callback) { - - this.startDate = moment().startOf('day'); - this.endDate = moment().endOf('day'); - this.timeZone = moment().zone(); - this.minDate = false; - this.maxDate = false; - this.dateLimit = false; - - this.showDropdowns = false; - this.showWeekNumbers = false; - this.timePicker = false; - this.timePickerSeconds = false; - this.timePickerIncrement = 30; - this.timePicker12Hour = true; - this.singleDatePicker = false; - this.ranges = {}; - - this.opens = 'right'; - if (this.element.hasClass('pull-right')) - this.opens = 'left'; - - this.buttonClasses = ['btn', 'btn-small btn-sm']; - this.applyClass = 'btn-success'; - this.cancelClass = 'btn-default'; - - this.format = 'MM/DD/YYYY'; - this.separator = ' - '; - - this.locale = { - applyLabel: 'Apply', - cancelLabel: 'Cancel', - fromLabel: 'From', - toLabel: 'To', - weekLabel: 'W', - customRangeLabel: 'Custom Range', - daysOfWeek: moment.weekdaysMin(), - monthNames: moment.monthsShort(), - firstDay: moment.localeData()._week.dow - }; - - this.cb = function () { }; - - if (typeof options.format === 'string') - this.format = options.format; - - if (typeof options.separator === 'string') - this.separator = options.separator; - - if (typeof options.startDate === 'string') - this.startDate = moment(options.startDate, this.format); - - if (typeof options.endDate === 'string') - this.endDate = moment(options.endDate, this.format); - - if (typeof options.minDate === 'string') - this.minDate = moment(options.minDate, this.format); - - if (typeof options.maxDate === 'string') - this.maxDate = moment(options.maxDate, this.format); - - if (typeof options.startDate === 'object') - this.startDate = moment(options.startDate); - - if (typeof options.endDate === 'object') - this.endDate = moment(options.endDate); - - if (typeof options.minDate === 'object') - this.minDate = moment(options.minDate); - - if (typeof options.maxDate === 'object') - this.maxDate = moment(options.maxDate); - - if (typeof options.applyClass === 'string') - this.applyClass = options.applyClass; - - if (typeof options.cancelClass === 'string') - this.cancelClass = options.cancelClass; - - if (typeof options.dateLimit === 'object') - this.dateLimit = options.dateLimit; - - if (typeof options.locale === 'object') { - - if (typeof options.locale.daysOfWeek === 'object') { - // Create a copy of daysOfWeek to avoid modification of original - // options object for reusability in multiple daterangepicker instances - this.locale.daysOfWeek = options.locale.daysOfWeek.slice(); - } - - if (typeof options.locale.monthNames === 'object') { - this.locale.monthNames = options.locale.monthNames.slice(); - } - - if (typeof options.locale.firstDay === 'number') { - this.locale.firstDay = options.locale.firstDay; - } - - if (typeof options.locale.applyLabel === 'string') { - this.locale.applyLabel = options.locale.applyLabel; - } - - if (typeof options.locale.cancelLabel === 'string') { - this.locale.cancelLabel = options.locale.cancelLabel; - } - - if (typeof options.locale.fromLabel === 'string') { - this.locale.fromLabel = options.locale.fromLabel; - } - - if (typeof options.locale.toLabel === 'string') { - this.locale.toLabel = options.locale.toLabel; - } - - if (typeof options.locale.weekLabel === 'string') { - this.locale.weekLabel = options.locale.weekLabel; - } - - if (typeof options.locale.customRangeLabel === 'string') { - this.locale.customRangeLabel = options.locale.customRangeLabel; - } - } - - if (typeof options.opens === 'string') - this.opens = options.opens; - - if (typeof options.showWeekNumbers === 'boolean') { - this.showWeekNumbers = options.showWeekNumbers; - } - - if (typeof options.buttonClasses === 'string') { - this.buttonClasses = [options.buttonClasses]; - } - - if (typeof options.buttonClasses === 'object') { - this.buttonClasses = options.buttonClasses; - } - - if (typeof options.showDropdowns === 'boolean') { - this.showDropdowns = options.showDropdowns; - } - - if (typeof options.singleDatePicker === 'boolean') { - this.singleDatePicker = options.singleDatePicker; - if (this.singleDatePicker) { - this.endDate = this.startDate.clone(); - } - } - - if (typeof options.timePicker === 'boolean') { - this.timePicker = options.timePicker; - } - - if (typeof options.timePickerSeconds === 'boolean') { - this.timePickerSeconds = options.timePickerSeconds; - } - - if (typeof options.timePickerIncrement === 'number') { - this.timePickerIncrement = options.timePickerIncrement; - } - - if (typeof options.timePicker12Hour === 'boolean') { - this.timePicker12Hour = options.timePicker12Hour; - } - - // update day names order to firstDay - if (this.locale.firstDay != 0) { - var iterator = this.locale.firstDay; - while (iterator > 0) { - this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); - iterator--; - } - } - - var start, end, range; - - //if no start/end dates set, check if an input element contains initial values - if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') { - if ($(this.element).is('input[type=text]')) { - var val = $(this.element).val(), - split = val.split(this.separator); - - start = end = null; - - if (split.length == 2) { - start = moment(split[0], this.format); - end = moment(split[1], this.format); - } else if (this.singleDatePicker && val !== "") { - start = moment(val, this.format); - end = moment(val, this.format); - } - if (start !== null && end !== null) { - this.startDate = start; - this.endDate = end; - } - } - } - - // bind the time zone used to build the calendar to either the timeZone passed in through the options or the zone of the startDate (which will be the local time zone by default) - if (typeof options.timeZone === 'string' || typeof options.timeZone === 'number') { - this.timeZone = options.timeZone; - this.startDate.zone(this.timeZone); - this.endDate.zone(this.timeZone); - } else { - this.timeZone = moment(this.startDate).zone(); - } - - if (typeof options.ranges === 'object') { - for (range in options.ranges) { - - if (typeof options.ranges[range][0] === 'string') - start = moment(options.ranges[range][0], this.format); - else - start = moment(options.ranges[range][0]); - - if (typeof options.ranges[range][1] === 'string') - end = moment(options.ranges[range][1], this.format); - else - end = moment(options.ranges[range][1]); - - // If we have a min/max date set, bound this range - // to it, but only if it would otherwise fall - // outside of the min/max. - if (this.minDate && start.isBefore(this.minDate)) - start = moment(this.minDate); - - if (this.maxDate && end.isAfter(this.maxDate)) - end = moment(this.maxDate); - - // If the end of the range is before the minimum (if min is set) OR - // the start of the range is after the max (also if set) don't display this - // range option. - if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) { - continue; - } - - this.ranges[range] = [start, end]; - } - - var list = '
    '; - for (range in this.ranges) { - list += '
  • ' + range + '
  • '; - } - list += '
  • ' + this.locale.customRangeLabel + '
  • '; - list += '
'; - this.container.find('.ranges ul').remove(); - this.container.find('.ranges').prepend(list); - } - - if (typeof callback === 'function') { - this.cb = callback; - } - - if (!this.timePicker) { - this.startDate = this.startDate.startOf('day'); - this.endDate = this.endDate.endOf('day'); - } - - if (this.singleDatePicker) { - this.opens = 'right'; - this.container.addClass('single'); - this.container.find('.calendar.right').show(); - this.container.find('.calendar.left').hide(); - if (!this.timePicker) { - this.container.find('.ranges').hide(); - } else { - this.container.find('.ranges .daterangepicker_start_input, .ranges .daterangepicker_end_input').hide(); - } - if (!this.container.find('.calendar.right').hasClass('single')) - this.container.find('.calendar.right').addClass('single'); - } else { - this.container.removeClass('single'); - this.container.find('.calendar.right').removeClass('single'); - this.container.find('.ranges').show(); - } - - this.oldStartDate = this.startDate.clone(); - this.oldEndDate = this.endDate.clone(); - this.oldChosenLabel = this.chosenLabel; - - this.leftCalendar = { - month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute(), this.startDate.second()]), - calendar: [] - }; - - this.rightCalendar = { - month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute(), this.endDate.second()]), - calendar: [] - }; - - if (this.opens == 'right' || this.opens == 'center') { - //swap calendar positions - var first = this.container.find('.calendar.first'); - var second = this.container.find('.calendar.second'); - - if (second.hasClass('single')) { - second.removeClass('single'); - first.addClass('single'); - } - - first.removeClass('left').addClass('right'); - second.removeClass('right').addClass('left'); - - if (this.singleDatePicker) { - first.show(); - second.hide(); - } - } - - if (typeof options.ranges === 'undefined' && !this.singleDatePicker) { - this.container.addClass('show-calendar'); - } - - this.container.addClass('opens' + this.opens); - - this.updateView(); - this.updateCalendars(); - - }, - - setStartDate: function(startDate) { - if (typeof startDate === 'string') - this.startDate = moment(startDate, this.format).zone(this.timeZone); - - if (typeof startDate === 'object') - this.startDate = moment(startDate); - - if (!this.timePicker) - this.startDate = this.startDate.startOf('day'); - - this.oldStartDate = this.startDate.clone(); - - this.updateView(); - this.updateCalendars(); - this.updateInputText(); - }, - - setEndDate: function(endDate) { - if (typeof endDate === 'string') - this.endDate = moment(endDate, this.format).zone(this.timeZone); - - if (typeof endDate === 'object') - this.endDate = moment(endDate); - - if (!this.timePicker) - this.endDate = this.endDate.endOf('day'); - - this.oldEndDate = this.endDate.clone(); - - this.updateView(); - this.updateCalendars(); - this.updateInputText(); - }, - - updateView: function () { - this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute()); - this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute()); - this.updateFormInputs(); - }, - - updateFormInputs: function () { - this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format)); - this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format)); - - if (this.startDate.isSame(this.endDate) || this.startDate.isBefore(this.endDate)) { - this.container.find('button.applyBtn').removeAttr('disabled'); - } else { - this.container.find('button.applyBtn').attr('disabled', 'disabled'); - } - }, - - updateFromControl: function () { - if (!this.element.is('input')) return; - if (!this.element.val().length) return; - - var dateString = this.element.val().split(this.separator), - start = null, - end = null; - - if(dateString.length === 2) { - start = moment(dateString[0], this.format).zone(this.timeZone); - end = moment(dateString[1], this.format).zone(this.timeZone); - } - - if (this.singleDatePicker || start === null || end === null) { - start = moment(this.element.val(), this.format).zone(this.timeZone); - end = start; - } - - if (end.isBefore(start)) return; - - this.oldStartDate = this.startDate.clone(); - this.oldEndDate = this.endDate.clone(); - - this.startDate = start; - this.endDate = end; - - if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) - this.notify(); - - this.updateCalendars(); - }, - - notify: function () { - this.updateView(); - this.cb(this.startDate, this.endDate, this.chosenLabel); - }, - - move: function () { - var parentOffset = { top: 0, left: 0 }; - var parentRightEdge = $(window).width(); - if (!this.parentEl.is('body')) { - parentOffset = { - top: this.parentEl.offset().top - this.parentEl.scrollTop(), - left: this.parentEl.offset().left - this.parentEl.scrollLeft() - }; - parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left; - } - - if (this.opens == 'left') { - this.container.css({ - top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, - right: parentRightEdge - this.element.offset().left - this.element.outerWidth(), - left: 'auto' - }); - if (this.container.offset().left < 0) { - this.container.css({ - right: 'auto', - left: 9 - }); - } - } else if (this.opens == 'center') { - this.container.css({ - top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, - left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2 - - this.container.outerWidth() / 2, - right: 'auto' - }); - if (this.container.offset().left < 0) { - this.container.css({ - right: 'auto', - left: 9 - }); - } - } else { - this.container.css({ - top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, - left: this.element.offset().left - parentOffset.left, - right: 'auto' - }); - if (this.container.offset().left + this.container.outerWidth() > $(window).width()) { - this.container.css({ - left: 'auto', - right: 0 - }); - } - } - }, - - toggle: function (e) { - if (this.element.hasClass('active')) { - this.hide(); - } else { - this.show(); - } - }, - - show: function (e) { - if (this.isShowing) return; - - this.element.addClass('active'); - this.container.show(); - this.move(); - - // Create a click proxy that is private to this instance of datepicker, for unbinding - this._outsideClickProxy = $.proxy(function (e) { this.outsideClick(e); }, this); - // Bind global datepicker mousedown for hiding and - $(document) - .on('mousedown.daterangepicker', this._outsideClickProxy) - // also support mobile devices - .on('touchend.daterangepicker', this._outsideClickProxy) - // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them - .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy) - // and also close when focus changes to outside the picker (eg. tabbing between controls) - .on('focusin.daterangepicker', this._outsideClickProxy); - - this.isShowing = true; - this.element.trigger('show.daterangepicker', this); - }, - - outsideClick: function (e) { - var target = $(e.target); - // if the page is clicked anywhere except within the daterangerpicker/button - // itself then call this.hide() - if ( - // ie modal dialog fix - e.type == "focusin" || - target.closest(this.element).length || - target.closest(this.container).length || - target.closest('.calendar-date').length - ) return; - this.hide(); - }, - - hide: function (e) { - if (!this.isShowing) return; - - $(document) - .off('.daterangepicker'); - - this.element.removeClass('active'); - this.container.hide(); - - if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) - this.notify(); - - this.oldStartDate = this.startDate.clone(); - this.oldEndDate = this.endDate.clone(); - - this.isShowing = false; - this.element.trigger('hide.daterangepicker', this); - }, - - enterRange: function (e) { - // mouse pointer has entered a range label - var label = e.target.innerHTML; - if (label == this.locale.customRangeLabel) { - this.updateView(); - } else { - var dates = this.ranges[label]; - this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format)); - this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format)); - } - }, - - showCalendars: function() { - this.container.addClass('show-calendar'); - this.move(); - this.element.trigger('showCalendar.daterangepicker', this); - }, - - hideCalendars: function() { - this.container.removeClass('show-calendar'); - this.element.trigger('hideCalendar.daterangepicker', this); - }, - - // when a date is typed into the start to end date textboxes - inputsChanged: function (e) { - var el = $(e.target); - var date = moment(el.val(), this.format); - if (!date.isValid()) return; - - var startDate, endDate; - if (el.attr('name') === 'daterangepicker_start') { - startDate = date; - endDate = this.endDate; - } else { - startDate = this.startDate; - endDate = date; - } - this.setCustomDates(startDate, endDate); - }, - - inputsKeydown: function(e) { - if (e.keyCode === 13) { - this.inputsChanged(e); - this.notify(); - } - }, - - updateInputText: function() { - if (this.element.is('input') && !this.singleDatePicker) { - this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format)); - } else if (this.element.is('input')) { - this.element.val(this.endDate.format(this.format)); - } - }, - - clickRange: function (e) { - var label = e.target.innerHTML; - this.chosenLabel = label; - if (label == this.locale.customRangeLabel) { - this.showCalendars(); - } else { - var dates = this.ranges[label]; - - this.startDate = dates[0]; - this.endDate = dates[1]; - - if (!this.timePicker) { - this.startDate.startOf('day'); - this.endDate.endOf('day'); - } - - this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute()); - this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute()); - this.updateCalendars(); - - this.updateInputText(); - - this.hideCalendars(); - this.hide(); - this.element.trigger('apply.daterangepicker', this); - } - }, - - clickPrev: function (e) { - var cal = $(e.target).parents('.calendar'); - if (cal.hasClass('left')) { - this.leftCalendar.month.subtract(1, 'month'); - } else { - this.rightCalendar.month.subtract(1, 'month'); - } - this.updateCalendars(); - }, - - clickNext: function (e) { - var cal = $(e.target).parents('.calendar'); - if (cal.hasClass('left')) { - this.leftCalendar.month.add(1, 'month'); - } else { - this.rightCalendar.month.add(1, 'month'); - } - this.updateCalendars(); - }, - - hoverDate: function (e) { - var title = $(e.target).attr('data-title'); - var row = title.substr(1, 1); - var col = title.substr(3, 1); - var cal = $(e.target).parents('.calendar'); - - if (cal.hasClass('left')) { - this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format)); - } else { - this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format)); - } - }, - - setCustomDates: function(startDate, endDate) { - this.chosenLabel = this.locale.customRangeLabel; - if (startDate.isAfter(endDate)) { - var difference = this.endDate.diff(this.startDate); - endDate = moment(startDate).add(difference, 'ms'); - if (this.maxDate && endDate.isAfter(this.maxDate)) { - endDate = this.maxDate; - } - } - this.startDate = startDate; - this.endDate = endDate; - - this.updateView(); - this.updateCalendars(); - }, - - clickDate: function (e) { - var title = $(e.target).attr('data-title'); - var row = title.substr(1, 1); - var col = title.substr(3, 1); - var cal = $(e.target).parents('.calendar'); - - var startDate, endDate; - if (cal.hasClass('left')) { - startDate = this.leftCalendar.calendar[row][col]; - endDate = this.endDate; - if (typeof this.dateLimit === 'object') { - var maxDate = moment(startDate).add(this.dateLimit).startOf('day'); - if (endDate.isAfter(maxDate)) { - endDate = maxDate; - } - } - } else { - startDate = this.startDate; - endDate = this.rightCalendar.calendar[row][col]; - if (typeof this.dateLimit === 'object') { - var minDate = moment(endDate).subtract(this.dateLimit).startOf('day'); - if (startDate.isBefore(minDate)) { - startDate = minDate; - } - } - } - - if (this.singleDatePicker && cal.hasClass('left')) { - endDate = startDate.clone(); - } else if (this.singleDatePicker && cal.hasClass('right')) { - startDate = endDate.clone(); - } - - cal.find('td').removeClass('active'); - - $(e.target).addClass('active'); - - this.setCustomDates(startDate, endDate); - - if (!this.timePicker) - endDate.endOf('day'); - - if (this.singleDatePicker && !this.timePicker) - this.clickApply(); - }, - - clickApply: function (e) { - this.updateInputText(); - this.hide(); - this.element.trigger('apply.daterangepicker', this); - }, - - clickCancel: function (e) { - this.startDate = this.oldStartDate; - this.endDate = this.oldEndDate; - this.chosenLabel = this.oldChosenLabel; - this.updateView(); - this.updateCalendars(); - this.hide(); - this.element.trigger('cancel.daterangepicker', this); - }, - - updateMonthYear: function (e) { - var isLeft = $(e.target).closest('.calendar').hasClass('left'), - leftOrRight = isLeft ? 'left' : 'right', - cal = this.container.find('.calendar.'+leftOrRight); - - // Month must be Number for new moment versions - var month = parseInt(cal.find('.monthselect').val(), 10); - var year = cal.find('.yearselect').val(); - - this[leftOrRight+'Calendar'].month.month(month).year(year); - this.updateCalendars(); - }, - - updateTime: function(e) { - - var cal = $(e.target).closest('.calendar'), - isLeft = cal.hasClass('left'); - - var hour = parseInt(cal.find('.hourselect').val(), 10); - var minute = parseInt(cal.find('.minuteselect').val(), 10); - var second = 0; - - if (this.timePickerSeconds) { - second = parseInt(cal.find('.secondselect').val(), 10); - } - - if (this.timePicker12Hour) { - var ampm = cal.find('.ampmselect').val(); - if (ampm === 'PM' && hour < 12) - hour += 12; - if (ampm === 'AM' && hour === 12) - hour = 0; - } - - if (isLeft) { - var start = this.startDate.clone(); - start.hour(hour); - start.minute(minute); - start.second(second); - this.startDate = start; - this.leftCalendar.month.hour(hour).minute(minute).second(second); - if (this.singleDatePicker) - this.endDate = start.clone(); - } else { - var end = this.endDate.clone(); - end.hour(hour); - end.minute(minute); - end.second(second); - this.endDate = end; - if (this.singleDatePicker) - this.startDate = end.clone(); - this.rightCalendar.month.hour(hour).minute(minute).second(second); - } - - this.updateView(); - this.updateCalendars(); - }, - - updateCalendars: function () { - this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), this.leftCalendar.month.second(), 'left'); - this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), this.rightCalendar.month.second(), 'right'); - this.container.find('.calendar.left').empty().html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate, 'left')); - this.container.find('.calendar.right').empty().html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.singleDatePicker ? this.minDate : this.startDate, this.maxDate, 'right')); - - this.container.find('.ranges li').removeClass('active'); - var customRange = true; - var i = 0; - for (var range in this.ranges) { - if (this.timePicker) { - if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) { - customRange = false; - this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')') - .addClass('active').html(); - } - } else { - //ignore times when comparing dates if time picker is not enabled - if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) { - customRange = false; - this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')') - .addClass('active').html(); - } - } - i++; - } - if (customRange) { - this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html(); - this.showCalendars(); - } - }, - - buildCalendar: function (month, year, hour, minute, second, side) { - var daysInMonth = moment([year, month]).daysInMonth(); - var firstDay = moment([year, month, 1]); - var lastDay = moment([year, month, daysInMonth]); - var lastMonth = moment(firstDay).subtract(1, 'month').month(); - var lastYear = moment(firstDay).subtract(1, 'month').year(); - - var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth(); - - var dayOfWeek = firstDay.day(); - - var i; - - //initialize a 6 rows x 7 columns array for the calendar - var calendar = []; - calendar.firstDay = firstDay; - calendar.lastDay = lastDay; - - for (i = 0; i < 6; i++) { - calendar[i] = []; - } - - //populate the calendar with date objects - var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; - if (startDay > daysInLastMonth) - startDay -= 7; - - if (dayOfWeek == this.locale.firstDay) - startDay = daysInLastMonth - 6; - - var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]).zone(this.timeZone); - - var col, row; - for (i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) { - if (i > 0 && col % 7 === 0) { - col = 0; - row++; - } - calendar[row][col] = curDate.clone().hour(hour); - curDate.hour(12); - - if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') { - calendar[row][col] = this.minDate.clone(); - } - - if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') { - calendar[row][col] = this.maxDate.clone(); - } - - } - - return calendar; - }, - - renderDropdowns: function (selected, minDate, maxDate) { - var currentMonth = selected.month(); - var currentYear = selected.year(); - var maxYear = (maxDate && maxDate.year()) || (currentYear + 5); - var minYear = (minDate && minDate.year()) || (currentYear - 50); - - var monthHtml = '"; - - var yearHtml = ''; - - return monthHtml + yearHtml; - }, - - renderCalendar: function (calendar, selected, minDate, maxDate, side) { - - var html = '
'; - html += ''; - html += ''; - html += ''; - - // add empty cell for week number - if (this.showWeekNumbers) - html += ''; - - if (!minDate || minDate.isBefore(calendar.firstDay)) { - html += ''; - } else { - html += ''; - } - - var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY"); - - if (this.showDropdowns) { - dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate); - } - - html += ''; - if (!maxDate || maxDate.isAfter(calendar.lastDay)) { - html += ''; - } else { - html += ''; - } - - html += ''; - html += ''; - - // add week number label - if (this.showWeekNumbers) - html += ''; - - $.each(this.locale.daysOfWeek, function (index, dayOfWeek) { - html += ''; - }); - - html += ''; - html += ''; - html += ''; - - for (var row = 0; row < 6; row++) { - html += ''; - - // add week number - if (this.showWeekNumbers) - html += ''; - - for (var col = 0; col < 7; col++) { - var cname = 'available '; - cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off'; - - if ((minDate && calendar[row][col].isBefore(minDate, 'day')) || (maxDate && calendar[row][col].isAfter(maxDate, 'day'))) { - cname = ' off disabled '; - } else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) { - cname += ' active '; - if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) { - cname += ' start-date '; - } - if (calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) { - cname += ' end-date '; - } - } else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) { - cname += ' in-range '; - if (calendar[row][col].isSame(this.startDate)) { cname += ' start-date '; } - if (calendar[row][col].isSame(this.endDate)) { cname += ' end-date '; } - } - - var title = 'r' + row + 'c' + col; - html += ''; - } - html += ''; - } - - html += ''; - html += '
' + dateHtml + '
' + this.locale.weekLabel + '' + dayOfWeek + '
' + calendar[row][0].week() + '' + calendar[row][col].date() + '
'; - html += '
'; - - var i; - if (this.timePicker) { - - html += '
'; - html += ' : '; - - html += ' '; - - if (this.timePickerSeconds) { - html += ': '; - } - - if (this.timePicker12Hour) { - html += ''; - } - - html += '
'; - - } - - return html; - - }, - - remove: function() { - - this.container.remove(); - this.element.off('.daterangepicker'); - this.element.removeData('daterangepicker'); - - } - - }; - - $.fn.daterangepicker = function (options, cb) { - this.each(function () { - var el = $(this); - if (el.data('daterangepicker')) - el.data('daterangepicker').remove(); - el.data('daterangepicker', new DateRangePicker(el, options, cb)); - }); - return this; - }; - -})); +/** +* @version: 1.3.17 +* @author: Dan Grossman http://www.dangrossman.info/ +* @date: 2014-11-25 +* @copyright: Copyright (c) 2012-2014 Dan Grossman. All rights reserved. +* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php +* @website: http://www.improvely.com/ +*/ + +(function(root, factory) { + + if (typeof define === 'function' && define.amd) { + define(['moment', 'jquery', 'exports'], function(momentjs, $, exports) { + root.daterangepicker = factory(root, exports, momentjs, $); + }); + + } else if (typeof exports !== 'undefined') { + var momentjs = require('moment'); + var jQuery; + try { + jQuery = require('jquery'); + } catch (err) { + jQuery = window.jQuery; + if (!jQuery) throw new Error('jQuery dependency not found'); + } + + factory(root, exports, momentjs, jQuery); + + // Finally, as a browser global. + } else { + root.daterangepicker = factory(root, {}, root.moment, (root.jQuery || root.Zepto || root.ender || root.$)); + } + +}(this, function(root, daterangepicker, moment, $) { + + var DateRangePicker = function (element, options, cb) { + + // by default, the daterangepicker element is placed at the bottom of HTML body + this.parentEl = 'body'; + + //element that triggered the date range picker + this.element = $(element); + + //tracks visible state + this.isShowing = false; + + //create the picker HTML object + var DRPTemplate = ''; + + //custom options + if (typeof options !== 'object' || options === null) + options = {}; + + this.parentEl = (typeof options === 'object' && options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl); + this.container = $(DRPTemplate).appendTo(this.parentEl); + + this.setOptions(options, cb); + + //apply CSS classes and labels to buttons + var c = this.container; + $.each(this.buttonClasses, function (idx, val) { + c.find('button').addClass(val); + }); + this.container.find('.daterangepicker_start_input label').html(this.locale.fromLabel); + this.container.find('.daterangepicker_end_input label').html(this.locale.toLabel); + if (this.applyClass.length) + this.container.find('.applyBtn').addClass(this.applyClass); + if (this.cancelClass.length) + this.container.find('.cancelBtn').addClass(this.cancelClass); + this.container.find('.applyBtn').html(this.locale.applyLabel); + this.container.find('.cancelBtn').html(this.locale.cancelLabel); + + //event listeners + + this.container.find('.calendar') + .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this)) + .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this)) + .on('click.daterangepicker', 'td.available', $.proxy(this.clickDate, this)) + .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this)) + .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this)) + .on('change.daterangepicker', 'select.yearselect', $.proxy(this.updateMonthYear, this)) + .on('change.daterangepicker', 'select.monthselect', $.proxy(this.updateMonthYear, this)) + .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.updateTime, this)); + + this.container.find('.ranges') + .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this)) + .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this)) + .on('click.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.showCalendars, this)) + .on('change.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.inputsChanged, this)) + .on('keydown.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.inputsKeydown, this)) + .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this)) + .on('mouseenter.daterangepicker', 'li', $.proxy(this.enterRange, this)) + .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this)); + + if (this.element.is('input')) { + this.element.on({ + 'click.daterangepicker': $.proxy(this.show, this), + 'focus.daterangepicker': $.proxy(this.show, this), + 'keyup.daterangepicker': $.proxy(this.updateFromControl, this) + }); + } else { + this.element.on('click.daterangepicker', $.proxy(this.toggle, this)); + } + + }; + + DateRangePicker.prototype = { + + constructor: DateRangePicker, + + setOptions: function(options, callback) { + + this.startDate = moment().startOf('day'); + this.endDate = moment().endOf('day'); + this.timeZone = moment().zone(); + this.minDate = false; + this.maxDate = false; + this.dateLimit = false; + + this.showDropdowns = false; + this.showWeekNumbers = false; + this.timePicker = false; + this.timePickerSeconds = false; + this.timePickerIncrement = 30; + this.timePicker12Hour = true; + this.singleDatePicker = false; + this.ranges = {}; + + this.opens = 'right'; + if (this.element.hasClass('pull-right')) + this.opens = 'left'; + + this.buttonClasses = ['btn', 'btn-small btn-sm']; + this.applyClass = 'btn-success'; + this.cancelClass = 'btn-default'; + + this.format = 'MM/DD/YYYY'; + this.separator = ' - '; + + this.locale = { + applyLabel: 'Apply', + cancelLabel: 'Cancel', + fromLabel: 'From', + toLabel: 'To', + weekLabel: 'W', + customRangeLabel: 'Custom Range', + daysOfWeek: moment.weekdaysMin(), + monthNames: moment.monthsShort(), + firstDay: moment.localeData()._week.dow + }; + + this.cb = function () { }; + + if (typeof options.format === 'string') + this.format = options.format; + + if (typeof options.separator === 'string') + this.separator = options.separator; + + if (typeof options.startDate === 'string') + this.startDate = moment(options.startDate, this.format); + + if (typeof options.endDate === 'string') + this.endDate = moment(options.endDate, this.format); + + if (typeof options.minDate === 'string') + this.minDate = moment(options.minDate, this.format); + + if (typeof options.maxDate === 'string') + this.maxDate = moment(options.maxDate, this.format); + + if (typeof options.startDate === 'object') + this.startDate = moment(options.startDate); + + if (typeof options.endDate === 'object') + this.endDate = moment(options.endDate); + + if (typeof options.minDate === 'object') + this.minDate = moment(options.minDate); + + if (typeof options.maxDate === 'object') + this.maxDate = moment(options.maxDate); + + if (typeof options.applyClass === 'string') + this.applyClass = options.applyClass; + + if (typeof options.cancelClass === 'string') + this.cancelClass = options.cancelClass; + + if (typeof options.dateLimit === 'object') + this.dateLimit = options.dateLimit; + + if (typeof options.locale === 'object') { + + if (typeof options.locale.daysOfWeek === 'object') { + // Create a copy of daysOfWeek to avoid modification of original + // options object for reusability in multiple daterangepicker instances + this.locale.daysOfWeek = options.locale.daysOfWeek.slice(); + } + + if (typeof options.locale.monthNames === 'object') { + this.locale.monthNames = options.locale.monthNames.slice(); + } + + if (typeof options.locale.firstDay === 'number') { + this.locale.firstDay = options.locale.firstDay; + } + + if (typeof options.locale.applyLabel === 'string') { + this.locale.applyLabel = options.locale.applyLabel; + } + + if (typeof options.locale.cancelLabel === 'string') { + this.locale.cancelLabel = options.locale.cancelLabel; + } + + if (typeof options.locale.fromLabel === 'string') { + this.locale.fromLabel = options.locale.fromLabel; + } + + if (typeof options.locale.toLabel === 'string') { + this.locale.toLabel = options.locale.toLabel; + } + + if (typeof options.locale.weekLabel === 'string') { + this.locale.weekLabel = options.locale.weekLabel; + } + + if (typeof options.locale.customRangeLabel === 'string') { + this.locale.customRangeLabel = options.locale.customRangeLabel; + } + } + + if (typeof options.opens === 'string') + this.opens = options.opens; + + if (typeof options.showWeekNumbers === 'boolean') { + this.showWeekNumbers = options.showWeekNumbers; + } + + if (typeof options.buttonClasses === 'string') { + this.buttonClasses = [options.buttonClasses]; + } + + if (typeof options.buttonClasses === 'object') { + this.buttonClasses = options.buttonClasses; + } + + if (typeof options.showDropdowns === 'boolean') { + this.showDropdowns = options.showDropdowns; + } + + if (typeof options.singleDatePicker === 'boolean') { + this.singleDatePicker = options.singleDatePicker; + if (this.singleDatePicker) { + this.endDate = this.startDate.clone(); + } + } + + if (typeof options.timePicker === 'boolean') { + this.timePicker = options.timePicker; + } + + if (typeof options.timePickerSeconds === 'boolean') { + this.timePickerSeconds = options.timePickerSeconds; + } + + if (typeof options.timePickerIncrement === 'number') { + this.timePickerIncrement = options.timePickerIncrement; + } + + if (typeof options.timePicker12Hour === 'boolean') { + this.timePicker12Hour = options.timePicker12Hour; + } + + // update day names order to firstDay + if (this.locale.firstDay != 0) { + var iterator = this.locale.firstDay; + while (iterator > 0) { + this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); + iterator--; + } + } + + var start, end, range; + + //if no start/end dates set, check if an input element contains initial values + if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') { + if ($(this.element).is('input[type=text]')) { + var val = $(this.element).val(), + split = val.split(this.separator); + + start = end = null; + + if (split.length == 2) { + start = moment(split[0], this.format); + end = moment(split[1], this.format); + } else if (this.singleDatePicker && val !== "") { + start = moment(val, this.format); + end = moment(val, this.format); + } + if (start !== null && end !== null) { + this.startDate = start; + this.endDate = end; + } + } + } + + // bind the time zone used to build the calendar to either the timeZone passed in through the options or the zone of the startDate (which will be the local time zone by default) + if (typeof options.timeZone === 'string' || typeof options.timeZone === 'number') { + this.timeZone = options.timeZone; + this.startDate.zone(this.timeZone); + this.endDate.zone(this.timeZone); + } else { + this.timeZone = moment(this.startDate).zone(); + } + + if (typeof options.ranges === 'object') { + for (range in options.ranges) { + + if (typeof options.ranges[range][0] === 'string') + start = moment(options.ranges[range][0], this.format); + else + start = moment(options.ranges[range][0]); + + if (typeof options.ranges[range][1] === 'string') + end = moment(options.ranges[range][1], this.format); + else + end = moment(options.ranges[range][1]); + + // If we have a min/max date set, bound this range + // to it, but only if it would otherwise fall + // outside of the min/max. + if (this.minDate && start.isBefore(this.minDate)) + start = moment(this.minDate); + + if (this.maxDate && end.isAfter(this.maxDate)) + end = moment(this.maxDate); + + // If the end of the range is before the minimum (if min is set) OR + // the start of the range is after the max (also if set) don't display this + // range option. + if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) { + continue; + } + + this.ranges[range] = [start, end]; + } + + var list = '
    '; + for (range in this.ranges) { + list += '
  • ' + range + '
  • '; + } + list += '
  • ' + this.locale.customRangeLabel + '
  • '; + list += '
'; + this.container.find('.ranges ul').remove(); + this.container.find('.ranges').prepend(list); + } + + if (typeof callback === 'function') { + this.cb = callback; + } + + if (!this.timePicker) { + this.startDate = this.startDate.startOf('day'); + this.endDate = this.endDate.endOf('day'); + } + + if (this.singleDatePicker) { + this.opens = 'right'; + this.container.addClass('single'); + this.container.find('.calendar.right').show(); + this.container.find('.calendar.left').hide(); + if (!this.timePicker) { + this.container.find('.ranges').hide(); + } else { + this.container.find('.ranges .daterangepicker_start_input, .ranges .daterangepicker_end_input').hide(); + } + if (!this.container.find('.calendar.right').hasClass('single')) + this.container.find('.calendar.right').addClass('single'); + } else { + this.container.removeClass('single'); + this.container.find('.calendar.right').removeClass('single'); + this.container.find('.ranges').show(); + } + + this.oldStartDate = this.startDate.clone(); + this.oldEndDate = this.endDate.clone(); + this.oldChosenLabel = this.chosenLabel; + + this.leftCalendar = { + month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute(), this.startDate.second()]), + calendar: [] + }; + + this.rightCalendar = { + month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute(), this.endDate.second()]), + calendar: [] + }; + + if (this.opens == 'right' || this.opens == 'center') { + //swap calendar positions + var first = this.container.find('.calendar.first'); + var second = this.container.find('.calendar.second'); + + if (second.hasClass('single')) { + second.removeClass('single'); + first.addClass('single'); + } + + first.removeClass('left').addClass('right'); + second.removeClass('right').addClass('left'); + + if (this.singleDatePicker) { + first.show(); + second.hide(); + } + } + + if (typeof options.ranges === 'undefined' && !this.singleDatePicker) { + this.container.addClass('show-calendar'); + } + + this.container.addClass('opens' + this.opens); + + this.updateView(); + this.updateCalendars(); + + }, + + setStartDate: function(startDate) { + if (typeof startDate === 'string') + this.startDate = moment(startDate, this.format).zone(this.timeZone); + + if (typeof startDate === 'object') + this.startDate = moment(startDate); + + if (!this.timePicker) + this.startDate = this.startDate.startOf('day'); + + this.oldStartDate = this.startDate.clone(); + + this.updateView(); + this.updateCalendars(); + this.updateInputText(); + }, + + setEndDate: function(endDate) { + if (typeof endDate === 'string') + this.endDate = moment(endDate, this.format).zone(this.timeZone); + + if (typeof endDate === 'object') + this.endDate = moment(endDate); + + if (!this.timePicker) + this.endDate = this.endDate.endOf('day'); + + this.oldEndDate = this.endDate.clone(); + + this.updateView(); + this.updateCalendars(); + this.updateInputText(); + }, + + updateView: function () { + this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute()); + this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute()); + this.updateFormInputs(); + }, + + updateFormInputs: function () { + this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format)); + this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format)); + + if (this.startDate.isSame(this.endDate) || this.startDate.isBefore(this.endDate)) { + this.container.find('button.applyBtn').removeAttr('disabled'); + } else { + this.container.find('button.applyBtn').attr('disabled', 'disabled'); + } + }, + + updateFromControl: function () { + if (!this.element.is('input')) return; + if (!this.element.val().length) return; + + var dateString = this.element.val().split(this.separator), + start = null, + end = null; + + if(dateString.length === 2) { + start = moment(dateString[0], this.format).zone(this.timeZone); + end = moment(dateString[1], this.format).zone(this.timeZone); + } + + if (this.singleDatePicker || start === null || end === null) { + start = moment(this.element.val(), this.format).zone(this.timeZone); + end = start; + } + + if (end.isBefore(start)) return; + + this.oldStartDate = this.startDate.clone(); + this.oldEndDate = this.endDate.clone(); + + this.startDate = start; + this.endDate = end; + + if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) + this.notify(); + + this.updateCalendars(); + }, + + notify: function () { + this.updateView(); + this.cb(this.startDate, this.endDate, this.chosenLabel); + }, + + move: function () { + var parentOffset = { top: 0, left: 0 }; + var parentRightEdge = $(window).width(); + if (!this.parentEl.is('body')) { + parentOffset = { + top: this.parentEl.offset().top - this.parentEl.scrollTop(), + left: this.parentEl.offset().left - this.parentEl.scrollLeft() + }; + parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left; + } + + if (this.opens == 'left') { + this.container.css({ + top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, + right: parentRightEdge - this.element.offset().left - this.element.outerWidth(), + left: 'auto' + }); + if (this.container.offset().left < 0) { + this.container.css({ + right: 'auto', + left: 9 + }); + } + } else if (this.opens == 'center') { + this.container.css({ + top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, + left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2 + - this.container.outerWidth() / 2, + right: 'auto' + }); + if (this.container.offset().left < 0) { + this.container.css({ + right: 'auto', + left: 9 + }); + } + } else { + this.container.css({ + top: this.element.offset().top + this.element.outerHeight() - parentOffset.top, + left: this.element.offset().left - parentOffset.left, + right: 'auto' + }); + if (this.container.offset().left + this.container.outerWidth() > $(window).width()) { + this.container.css({ + left: 'auto', + right: 0 + }); + } + } + }, + + toggle: function (e) { + if (this.element.hasClass('active')) { + this.hide(); + } else { + this.show(); + } + }, + + show: function (e) { + if (this.isShowing) return; + + this.element.addClass('active'); + this.container.show(); + this.move(); + + // Create a click proxy that is private to this instance of datepicker, for unbinding + this._outsideClickProxy = $.proxy(function (e) { this.outsideClick(e); }, this); + // Bind global datepicker mousedown for hiding and + $(document) + .on('mousedown.daterangepicker', this._outsideClickProxy) + // also support mobile devices + .on('touchend.daterangepicker', this._outsideClickProxy) + // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them + .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy) + // and also close when focus changes to outside the picker (eg. tabbing between controls) + .on('focusin.daterangepicker', this._outsideClickProxy); + + this.isShowing = true; + this.element.trigger('show.daterangepicker', this); + }, + + outsideClick: function (e) { + var target = $(e.target); + // if the page is clicked anywhere except within the daterangerpicker/button + // itself then call this.hide() + if ( + // ie modal dialog fix + e.type == "focusin" || + target.closest(this.element).length || + target.closest(this.container).length || + target.closest('.calendar-date').length + ) return; + this.hide(); + }, + + hide: function (e) { + if (!this.isShowing) return; + + $(document) + .off('.daterangepicker'); + + this.element.removeClass('active'); + this.container.hide(); + + if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) + this.notify(); + + this.oldStartDate = this.startDate.clone(); + this.oldEndDate = this.endDate.clone(); + + this.isShowing = false; + this.element.trigger('hide.daterangepicker', this); + }, + + enterRange: function (e) { + // mouse pointer has entered a range label + var label = e.target.innerHTML; + if (label == this.locale.customRangeLabel) { + this.updateView(); + } else { + var dates = this.ranges[label]; + this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format)); + this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format)); + } + }, + + showCalendars: function() { + this.container.addClass('show-calendar'); + this.move(); + this.element.trigger('showCalendar.daterangepicker', this); + }, + + hideCalendars: function() { + this.container.removeClass('show-calendar'); + this.element.trigger('hideCalendar.daterangepicker', this); + }, + + // when a date is typed into the start to end date textboxes + inputsChanged: function (e) { + var el = $(e.target); + var date = moment(el.val(), this.format); + if (!date.isValid()) return; + + var startDate, endDate; + if (el.attr('name') === 'daterangepicker_start') { + startDate = date; + endDate = this.endDate; + } else { + startDate = this.startDate; + endDate = date; + } + this.setCustomDates(startDate, endDate); + }, + + inputsKeydown: function(e) { + if (e.keyCode === 13) { + this.inputsChanged(e); + this.notify(); + } + }, + + updateInputText: function() { + if (this.element.is('input') && !this.singleDatePicker) { + this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format)); + } else if (this.element.is('input')) { + this.element.val(this.endDate.format(this.format)); + } + }, + + clickRange: function (e) { + var label = e.target.innerHTML; + this.chosenLabel = label; + if (label == this.locale.customRangeLabel) { + this.showCalendars(); + } else { + var dates = this.ranges[label]; + + this.startDate = dates[0]; + this.endDate = dates[1]; + + if (!this.timePicker) { + this.startDate.startOf('day'); + this.endDate.endOf('day'); + } + + this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute()); + this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute()); + this.updateCalendars(); + + this.updateInputText(); + + this.hideCalendars(); + this.hide(); + this.element.trigger('apply.daterangepicker', this); + } + }, + + clickPrev: function (e) { + var cal = $(e.target).parents('.calendar'); + if (cal.hasClass('left')) { + this.leftCalendar.month.subtract(1, 'month'); + } else { + this.rightCalendar.month.subtract(1, 'month'); + } + this.updateCalendars(); + }, + + clickNext: function (e) { + var cal = $(e.target).parents('.calendar'); + if (cal.hasClass('left')) { + this.leftCalendar.month.add(1, 'month'); + } else { + this.rightCalendar.month.add(1, 'month'); + } + this.updateCalendars(); + }, + + hoverDate: function (e) { + var title = $(e.target).attr('data-title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(e.target).parents('.calendar'); + + if (cal.hasClass('left')) { + this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format)); + } else { + this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format)); + } + }, + + setCustomDates: function(startDate, endDate) { + this.chosenLabel = this.locale.customRangeLabel; + if (startDate.isAfter(endDate)) { + var difference = this.endDate.diff(this.startDate); + endDate = moment(startDate).add(difference, 'ms'); + if (this.maxDate && endDate.isAfter(this.maxDate)) { + endDate = this.maxDate; + } + } + this.startDate = startDate; + this.endDate = endDate; + + this.updateView(); + this.updateCalendars(); + }, + + clickDate: function (e) { + var title = $(e.target).attr('data-title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(e.target).parents('.calendar'); + + var startDate, endDate; + if (cal.hasClass('left')) { + startDate = this.leftCalendar.calendar[row][col]; + endDate = this.endDate; + if (typeof this.dateLimit === 'object') { + var maxDate = moment(startDate).add(this.dateLimit).startOf('day'); + if (endDate.isAfter(maxDate)) { + endDate = maxDate; + } + } + } else { + startDate = this.startDate; + endDate = this.rightCalendar.calendar[row][col]; + if (typeof this.dateLimit === 'object') { + var minDate = moment(endDate).subtract(this.dateLimit).startOf('day'); + if (startDate.isBefore(minDate)) { + startDate = minDate; + } + } + } + + if (this.singleDatePicker && cal.hasClass('left')) { + endDate = startDate.clone(); + } else if (this.singleDatePicker && cal.hasClass('right')) { + startDate = endDate.clone(); + } + + cal.find('td').removeClass('active'); + + $(e.target).addClass('active'); + + this.setCustomDates(startDate, endDate); + + if (!this.timePicker) + endDate.endOf('day'); + + if (this.singleDatePicker && !this.timePicker) + this.clickApply(); + }, + + clickApply: function (e) { + this.updateInputText(); + this.hide(); + this.element.trigger('apply.daterangepicker', this); + }, + + clickCancel: function (e) { + this.startDate = this.oldStartDate; + this.endDate = this.oldEndDate; + this.chosenLabel = this.oldChosenLabel; + this.updateView(); + this.updateCalendars(); + this.hide(); + this.element.trigger('cancel.daterangepicker', this); + }, + + updateMonthYear: function (e) { + var isLeft = $(e.target).closest('.calendar').hasClass('left'), + leftOrRight = isLeft ? 'left' : 'right', + cal = this.container.find('.calendar.'+leftOrRight); + + // Month must be Number for new moment versions + var month = parseInt(cal.find('.monthselect').val(), 10); + var year = cal.find('.yearselect').val(); + + this[leftOrRight+'Calendar'].month.month(month).year(year); + this.updateCalendars(); + }, + + updateTime: function(e) { + + var cal = $(e.target).closest('.calendar'), + isLeft = cal.hasClass('left'); + + var hour = parseInt(cal.find('.hourselect').val(), 10); + var minute = parseInt(cal.find('.minuteselect').val(), 10); + var second = 0; + + if (this.timePickerSeconds) { + second = parseInt(cal.find('.secondselect').val(), 10); + } + + if (this.timePicker12Hour) { + var ampm = cal.find('.ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + + if (isLeft) { + var start = this.startDate.clone(); + start.hour(hour); + start.minute(minute); + start.second(second); + this.startDate = start; + this.leftCalendar.month.hour(hour).minute(minute).second(second); + if (this.singleDatePicker) + this.endDate = start.clone(); + } else { + var end = this.endDate.clone(); + end.hour(hour); + end.minute(minute); + end.second(second); + this.endDate = end; + if (this.singleDatePicker) + this.startDate = end.clone(); + this.rightCalendar.month.hour(hour).minute(minute).second(second); + } + + this.updateView(); + this.updateCalendars(); + }, + + updateCalendars: function () { + this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), this.leftCalendar.month.second(), 'left'); + this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), this.rightCalendar.month.second(), 'right'); + this.container.find('.calendar.left').empty().html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate, 'left')); + this.container.find('.calendar.right').empty().html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.singleDatePicker ? this.minDate : this.startDate, this.maxDate, 'right')); + + this.container.find('.ranges li').removeClass('active'); + var customRange = true; + var i = 0; + for (var range in this.ranges) { + if (this.timePicker) { + if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) { + customRange = false; + this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')') + .addClass('active').html(); + } + } else { + //ignore times when comparing dates if time picker is not enabled + if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) { + customRange = false; + this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')') + .addClass('active').html(); + } + } + i++; + } + if (customRange) { + this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html(); + this.showCalendars(); + } + }, + + buildCalendar: function (month, year, hour, minute, second, side) { + var daysInMonth = moment([year, month]).daysInMonth(); + var firstDay = moment([year, month, 1]); + var lastDay = moment([year, month, daysInMonth]); + var lastMonth = moment(firstDay).subtract(1, 'month').month(); + var lastYear = moment(firstDay).subtract(1, 'month').year(); + + var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth(); + + var dayOfWeek = firstDay.day(); + + var i; + + //initialize a 6 rows x 7 columns array for the calendar + var calendar = []; + calendar.firstDay = firstDay; + calendar.lastDay = lastDay; + + for (i = 0; i < 6; i++) { + calendar[i] = []; + } + + //populate the calendar with date objects + var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; + if (startDay > daysInLastMonth) + startDay -= 7; + + if (dayOfWeek == this.locale.firstDay) + startDay = daysInLastMonth - 6; + + var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]).zone(this.timeZone); + + var col, row; + for (i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) { + if (i > 0 && col % 7 === 0) { + col = 0; + row++; + } + calendar[row][col] = curDate.clone().hour(hour); + curDate.hour(12); + + if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') { + calendar[row][col] = this.minDate.clone(); + } + + if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') { + calendar[row][col] = this.maxDate.clone(); + } + + } + + return calendar; + }, + + renderDropdowns: function (selected, minDate, maxDate) { + var currentMonth = selected.month(); + var currentYear = selected.year(); + var maxYear = (maxDate && maxDate.year()) || (currentYear + 5); + var minYear = (minDate && minDate.year()) || (currentYear - 50); + + var monthHtml = '"; + + var yearHtml = ''; + + return monthHtml + yearHtml; + }, + + renderCalendar: function (calendar, selected, minDate, maxDate, side) { + + var html = '
'; + html += ''; + html += ''; + html += ''; + + // add empty cell for week number + if (this.showWeekNumbers) + html += ''; + + if (!minDate || minDate.isBefore(calendar.firstDay)) { + html += ''; + } else { + html += ''; + } + + var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY"); + + if (this.showDropdowns) { + dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate); + } + + html += ''; + if (!maxDate || maxDate.isAfter(calendar.lastDay)) { + html += ''; + } else { + html += ''; + } + + html += ''; + html += ''; + + // add week number label + if (this.showWeekNumbers) + html += ''; + + $.each(this.locale.daysOfWeek, function (index, dayOfWeek) { + html += ''; + }); + + html += ''; + html += ''; + html += ''; + + for (var row = 0; row < 6; row++) { + html += ''; + + // add week number + if (this.showWeekNumbers) + html += ''; + + for (var col = 0; col < 7; col++) { + var cname = 'available '; + cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off'; + + if ((minDate && calendar[row][col].isBefore(minDate, 'day')) || (maxDate && calendar[row][col].isAfter(maxDate, 'day'))) { + cname = ' off disabled '; + } else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) { + cname += ' active '; + if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) { + cname += ' start-date '; + } + if (calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) { + cname += ' end-date '; + } + } else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) { + cname += ' in-range '; + if (calendar[row][col].isSame(this.startDate)) { cname += ' start-date '; } + if (calendar[row][col].isSame(this.endDate)) { cname += ' end-date '; } + } + + var title = 'r' + row + 'c' + col; + html += ''; + } + html += ''; + } + + html += ''; + html += '
' + dateHtml + '
' + this.locale.weekLabel + '' + dayOfWeek + '
' + calendar[row][0].week() + '' + calendar[row][col].date() + '
'; + html += '
'; + + var i; + if (this.timePicker) { + + html += '
'; + html += ' : '; + + html += ' '; + + if (this.timePickerSeconds) { + html += ': '; + } + + if (this.timePicker12Hour) { + html += ''; + } + + html += '
'; + + } + + return html; + + }, + + remove: function() { + + this.container.remove(); + this.element.off('.daterangepicker'); + this.element.removeData('daterangepicker'); + + } + + }; + + $.fn.daterangepicker = function (options, cb) { + this.each(function () { + var el = $(this); + if (el.data('daterangepicker')) + el.data('daterangepicker').remove(); + el.data('daterangepicker', new DateRangePicker(el, options, cb)); + }); + return this; + }; + +})); diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/moment.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/moment.js index 1800b5de..6d94b173 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/moment.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/moment.js @@ -1,2808 +1,2808 @@ -//! moment.js -//! version : 2.8.1 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors -//! license : MIT -//! momentjs.com - -(function (undefined) { - /************************************ - Constants - ************************************/ - - var moment, - VERSION = '2.8.1', - // the global-scope this is NOT the global object in Node.js - globalScope = typeof global !== 'undefined' ? global : this, - oldGlobalMoment, - round = Math.round, - i, - - YEAR = 0, - MONTH = 1, - DATE = 2, - HOUR = 3, - MINUTE = 4, - SECOND = 5, - MILLISECOND = 6, - - // internal storage for locale config files - locales = {}, - - // extra moment internal properties (plugins register props here) - momentProperties = [], - - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module.exports), - - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, - - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, - - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, - - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenDigits = /\d+/, // nonzero number of digits - parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO separator) - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - parseTokenOrdinal = /\d{1,2}/, - - //strict parsing regexes - parseTokenOneDigit = /\d/, // 0 - 9 - parseTokenTwoDigits = /\d\d/, // 00 - 99 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{4}/, // 0000 - 9999 - parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 - parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf - - // iso 8601 regex - // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, - - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - - isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], - ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], - ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], - ['GGGG-[W]WW', /\d{4}-W\d{2}/], - ['YYYY-DDD', /\d{4}-\d{3}/] - ], - - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], - - // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, - - // getter and setter names - proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, - - unitAliases = { - ms : 'millisecond', - s : 'second', - m : 'minute', - h : 'hour', - d : 'day', - D : 'date', - w : 'week', - W : 'isoWeek', - M : 'month', - Q : 'quarter', - y : 'year', - DDD : 'dayOfYear', - e : 'weekday', - E : 'isoWeekday', - gg: 'weekYear', - GG: 'isoWeekYear' - }, - - camelFunctions = { - dayofyear : 'dayOfYear', - isoweekday : 'isoWeekday', - isoweek : 'isoWeek', - weekyear : 'weekYear', - isoweekyear : 'isoWeekYear' - }, - - // format function strings - formatFunctions = {}, - - // default relative time thresholds - relativeTimeThresholds = { - s: 45, // seconds to minute - m: 45, // minutes to hour - h: 22, // hours to day - d: 26, // days to month - M: 11 // months to year - }, - - // tokens to ordinalize and pad - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), - - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.localeData().monthsShort(this, format); - }, - MMMM : function (format) { - return this.localeData().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.localeData().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.localeData().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.localeData().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - YYYYYY : function () { - var y = this.year(), sign = y >= 0 ? '+' : '-'; - return sign + leftZeroFill(Math.abs(y), 6); - }, - gg : function () { - return leftZeroFill(this.weekYear() % 100, 2); - }, - gggg : function () { - return leftZeroFill(this.weekYear(), 4); - }, - ggggg : function () { - return leftZeroFill(this.weekYear(), 5); - }, - GG : function () { - return leftZeroFill(this.isoWeekYear() % 100, 2); - }, - GGGG : function () { - return leftZeroFill(this.isoWeekYear(), 4); - }, - GGGGG : function () { - return leftZeroFill(this.isoWeekYear(), 5); - }, - e : function () { - return this.weekday(); - }, - E : function () { - return this.isoWeekday(); - }, - a : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return toInt(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(toInt(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - SSSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = -this.zone(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); - }, - ZZ : function () { - var a = -this.zone(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); - }, - z : function () { - return this.zoneAbbr(); - }, - zz : function () { - return this.zoneName(); - }, - X : function () { - return this.unix(); - }, - Q : function () { - return this.quarter(); - } - }, - - deprecations = {}, - - lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; - - // Pick the first defined of two or three arguments. dfl comes from - // default. - function dfl(a, b, c) { - switch (arguments.length) { - case 2: return a != null ? a : b; - case 3: return a != null ? a : b != null ? b : c; - default: throw new Error('Implement me'); - } - } - - function defaultParsingFlags() { - // We need to deep clone this object, and es5 standard is not very - // helpful. - return { - empty : false, - unusedTokens : [], - unusedInput : [], - overflow : -2, - charsLeftOver : 0, - nullInput : false, - invalidMonth : null, - invalidFormat : false, - userInvalidated : false, - iso: false - }; - } - - function printMsg(msg) { - if (moment.suppressDeprecationWarnings === false && - typeof console !== 'undefined' && console.warn) { - console.warn("Deprecation warning: " + msg); - } - } - - function deprecate(msg, fn) { - var firstTime = true; - return extend(function () { - if (firstTime) { - printMsg(msg); - firstTime = false; - } - return fn.apply(this, arguments); - }, fn); - } - - function deprecateSimple(name, msg) { - if (!deprecations[name]) { - printMsg(msg); - deprecations[name] = true; - } - } - - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; - } - function ordinalizeToken(func, period) { - return function (a) { - return this.localeData().ordinal(func.call(this, a), period); - }; - } - - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); - } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); - } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - - - /************************************ - Constructors - ************************************/ - - function Locale() { - } - - // Moment prototype object - function Moment(config, skipOverflow) { - if (skipOverflow !== false) { - checkOverflow(config); - } - copyConfig(this, config); - this._d = new Date(+config._d); - } - - // Duration Constructor - function Duration(duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - quarters = normalizedInput.quarter || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - quarters * 3 + - years * 12; - - this._data = {}; - - this._locale = moment.localeData(); - - this._bubble(); - } - - /************************************ - Helpers - ************************************/ - - - function extend(a, b) { - for (var i in b) { - if (b.hasOwnProperty(i)) { - a[i] = b[i]; - } - } - - if (b.hasOwnProperty('toString')) { - a.toString = b.toString; - } - - if (b.hasOwnProperty('valueOf')) { - a.valueOf = b.valueOf; - } - - return a; - } - - function copyConfig(to, from) { - var i, prop, val; - - if (typeof from._isAMomentObject !== 'undefined') { - to._isAMomentObject = from._isAMomentObject; - } - if (typeof from._i !== 'undefined') { - to._i = from._i; - } - if (typeof from._f !== 'undefined') { - to._f = from._f; - } - if (typeof from._l !== 'undefined') { - to._l = from._l; - } - if (typeof from._strict !== 'undefined') { - to._strict = from._strict; - } - if (typeof from._tzm !== 'undefined') { - to._tzm = from._tzm; - } - if (typeof from._isUTC !== 'undefined') { - to._isUTC = from._isUTC; - } - if (typeof from._offset !== 'undefined') { - to._offset = from._offset; - } - if (typeof from._pf !== 'undefined') { - to._pf = from._pf; - } - if (typeof from._locale !== 'undefined') { - to._locale = from._locale; - } - - if (momentProperties.length > 0) { - for (i in momentProperties) { - prop = momentProperties[i]; - val = from[prop]; - if (typeof val !== 'undefined') { - to[prop] = val; - } - } - } - - return to; - } - - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } - } - - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength, forceSign) { - var output = '' + Math.abs(number), - sign = number >= 0; - - while (output.length < targetLength) { - output = '0' + output; - } - return (sign ? (forceSign ? '+' : '') : '-') + output; - } - - function positiveMomentsDifference(base, other) { - var res = {milliseconds: 0, months: 0}; - - res.months = other.month() - base.month() + - (other.year() - base.year()) * 12; - if (base.clone().add(res.months, 'M').isAfter(other)) { - --res.months; - } - - res.milliseconds = +other - +(base.clone().add(res.months, 'M')); - - return res; - } - - function momentsDifference(base, other) { - var res; - other = makeAs(other, base); - if (base.isBefore(other)) { - res = positiveMomentsDifference(base, other); - } else { - res = positiveMomentsDifference(other, base); - res.milliseconds = -res.milliseconds; - res.months = -res.months; - } - - return res; - } - - // TODO: remove 'name' arg after deprecation is removed - function createAdder(direction, name) { - return function (val, period) { - var dur, tmp; - //invert the arguments, but complain about it - if (period !== null && !isNaN(+period)) { - deprecateSimple(name, "moment()." + name + "(period, number) is deprecated. Please use moment()." + name + "(number, period)."); - tmp = val; val = period; period = tmp; - } - - val = typeof val === 'string' ? +val : val; - dur = moment.duration(val, period); - addOrSubtractDurationFromMoment(this, dur, direction); - return this; - }; - } - - function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { - var milliseconds = duration._milliseconds, - days = duration._days, - months = duration._months; - updateOffset = updateOffset == null ? true : updateOffset; - - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - if (days) { - rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); - } - if (months) { - rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); - } - if (updateOffset) { - moment.updateOffset(mom, days || months); - } - } - - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; - } - - function isDate(input) { - return Object.prototype.toString.call(input) === '[object Date]' || - input instanceof Date; - } - - // compare two arrays, return the number of differences - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ((dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { - diffs++; - } - } - return diffs + lengthDiff; - } - - function normalizeUnits(units) { - if (units) { - var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); - units = unitAliases[units] || camelFunctions[lowered] || lowered; - } - return units; - } - - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; - - for (prop in inputObject) { - if (inputObject.hasOwnProperty(prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; - } - } - } - - return normalizedInput; - } - - function makeList(field) { - var count, setter; - - if (field.indexOf('week') === 0) { - count = 7; - setter = 'day'; - } - else if (field.indexOf('month') === 0) { - count = 12; - setter = 'month'; - } - else { - return; - } - - moment[field] = function (format, index) { - var i, getter, - method = moment._locale[field], - results = []; - - if (typeof format === 'number') { - index = format; - format = undefined; - } - - getter = function (i) { - var m = moment().utc().set(setter, i); - return method.call(moment._locale, m, format || ''); - }; - - if (index != null) { - return getter(index); - } - else { - for (i = 0; i < count; i++) { - results.push(getter(i)); - } - return results; - } - }; - } - - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; - - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - if (coercedNumber >= 0) { - value = Math.floor(coercedNumber); - } else { - value = Math.ceil(coercedNumber); - } - } - - return value; - } - - function daysInMonth(year, month) { - return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); - } - - function weeksInYear(year, dow, doy) { - return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; - } - - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; - } - - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } - - function checkOverflow(m) { - var overflow; - if (m._a && m._pf.overflow === -2) { - overflow = - m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : - m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : - m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR : - m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : - m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : - m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : - -1; - - if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { - overflow = DATE; - } - - m._pf.overflow = overflow; - } - } - - function isValid(m) { - if (m._isValid == null) { - m._isValid = !isNaN(m._d.getTime()) && - m._pf.overflow < 0 && - !m._pf.empty && - !m._pf.invalidMonth && - !m._pf.nullInput && - !m._pf.invalidFormat && - !m._pf.userInvalidated; - - if (m._strict) { - m._isValid = m._isValid && - m._pf.charsLeftOver === 0 && - m._pf.unusedTokens.length === 0; - } - } - return m._isValid; - } - - function normalizeLocale(key) { - return key ? key.toLowerCase().replace('_', '-') : key; - } - - // pick the locale from the array - // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each - // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root - function chooseLocale(names) { - var i = 0, j, next, locale, split; - - while (i < names.length) { - split = normalizeLocale(names[i]).split('-'); - j = split.length; - next = normalizeLocale(names[i + 1]); - next = next ? next.split('-') : null; - while (j > 0) { - locale = loadLocale(split.slice(0, j).join('-')); - if (locale) { - return locale; - } - if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { - //the next array item is better than a shallower substring of this one - break; - } - j--; - } - i++; - } - return null; - } - - function loadLocale(name) { - var oldLocale = null; - if (!locales[name] && hasModule) { - try { - oldLocale = moment.locale(); - require('./locale/' + name); - // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales - moment.locale(oldLocale); - } catch (e) { } - } - return locales[name]; - } - - // Return a moment from input, that is local/utc/zone equivalent to model. - function makeAs(input, model) { - return model._isUTC ? moment(input).zone(model._offset || 0) : - moment(input).local(); - } - - /************************************ - Locale - ************************************/ - - - extend(Locale.prototype, { - - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - }, - - _months : '1_2_3_4_May_June_July_August_September_October_November_December'.split('_'), - months : function (m) { - return this._months[m.month()]; - }, - - _monthsShort : '1_2_3_4_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - monthsShort : function (m) { - return this._monthsShort[m.month()]; - }, - - monthsParse : function (monthName) { - var i, mom, regex; - - if (!this._monthsParse) { - this._monthsParse = []; - } - - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - if (!this._monthsParse[i]) { - mom = moment.utc([2000, i]); - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._monthsParse[i].test(monthName)) { - return i; - } - } - }, - - _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, - - _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysShort : function (m) { - return this._weekdaysShort[m.day()]; - }, - - _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - weekdaysMin : function (m) { - return this._weekdaysMin[m.day()]; - }, - - weekdaysParse : function (weekdayName) { - var i, mom, regex; - - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } - - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = moment([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - }, - - _longDateFormat : { - LT : 'h:mm A', - L : 'MM/DD/YYYY', - LL : 'MMMM D, YYYY', - LLL : 'MMMM D, YYYY LT', - LLLL : 'dddd, MMMM D, YYYY LT' - }, - longDateFormat : function (key) { - var output = this._longDateFormat[key]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, - - isPM : function (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - }, - - _meridiemParse : /[ap]\.?m?\.?/i, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, - - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom) : output; - }, - - _relativeTime : { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }, - - relativeTime : function (number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return (typeof output === 'function') ? - output(number, withoutSuffix, string, isFuture) : - output.replace(/%d/i, number); - }, - - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, - - ordinal : function (number) { - return this._ordinal.replace('%d', number); - }, - _ordinal : '%d', - - preparse : function (string) { - return string; - }, - - postformat : function (string) { - return string; - }, - - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - }, - - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - }, - - _invalidDate: 'Invalid date', - invalidDate: function () { - return this._invalidDate; - } - }); - - /************************************ - Formatting - ************************************/ - - - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ''); - } - return input.replace(/\\/g, ''); - } - - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; - - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } - - return function (mom) { - var output = ''; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; - } - - // format date using native date object - function formatMoment(m, format) { - if (!m.isValid()) { - return m.localeData().invalidDate(); - } - - format = expandFormat(format, m.localeData()); - - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } - - return formatFunctions[format](m); - } - - function expandFormat(format, locale) { - var i = 5; - - function replaceLongDateFormatTokens(input) { - return locale.longDateFormat(input) || input; - } - - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - localFormattingTokens.lastIndex = 0; - i -= 1; - } - - return format; - } - - - /************************************ - Parsing - ************************************/ - - - // get the regex to find the next token - function getParseRegexForToken(token, config) { - var a, strict = config._strict; - switch (token) { - case 'Q': - return parseTokenOneDigit; - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - case 'GGGG': - case 'gggg': - return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; - case 'Y': - case 'G': - case 'g': - return parseTokenSignedNumber; - case 'YYYYYY': - case 'YYYYY': - case 'GGGGG': - case 'ggggg': - return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; - case 'S': - if (strict) { - return parseTokenOneDigit; - } - /* falls through */ - case 'SS': - if (strict) { - return parseTokenTwoDigits; - } - /* falls through */ - case 'SSS': - if (strict) { - return parseTokenThreeDigits; - } - /* falls through */ - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - return parseTokenWord; - case 'a': - case 'A': - return config._locale._meridiemParse; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'SSSS': - return parseTokenDigits; - case 'MM': - case 'DD': - case 'YY': - case 'GG': - case 'gg': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'ww': - case 'WW': - return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - case 'w': - case 'W': - case 'e': - case 'E': - return parseTokenOneOrTwoDigits; - case 'Do': - return parseTokenOrdinal; - default : - a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); - return a; - } - } - - function timezoneMinutesFromString(string) { - string = string || ''; - var possibleTzMatches = (string.match(parseTokenTimezone) || []), - tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], - parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + toInt(parts[2]); - - return parts[0] === '+' ? -minutes : minutes; - } - - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, datePartArray = config._a; - - switch (token) { - // QUARTER - case 'Q': - if (input != null) { - datePartArray[MONTH] = (toInt(input) - 1) * 3; - } - break; - // MONTH - case 'M' : // fall through to MM - case 'MM' : - if (input != null) { - datePartArray[MONTH] = toInt(input) - 1; - } - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = config._locale.monthsParse(input); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[MONTH] = a; - } else { - config._pf.invalidMonth = input; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DD - case 'DD' : - if (input != null) { - datePartArray[DATE] = toInt(input); - } - break; - case 'Do' : - if (input != null) { - datePartArray[DATE] = toInt(parseInt(input, 10)); - } - break; - // DAY OF YEAR - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - config._dayOfYear = toInt(input); - } - - break; - // YEAR - case 'YY' : - datePartArray[YEAR] = moment.parseTwoDigitYear(input); - break; - case 'YYYY' : - case 'YYYYY' : - case 'YYYYYY' : - datePartArray[YEAR] = toInt(input); - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._isPm = config._locale.isPM(input); - break; - // 24 HOUR - case 'H' : // fall through to hh - case 'HH' : // fall through to hh - case 'h' : // fall through to hh - case 'hh' : - datePartArray[HOUR] = toInt(input); - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[MINUTE] = toInt(input); - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[SECOND] = toInt(input); - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - case 'SSSS' : - datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - config._tzm = timezoneMinutesFromString(input); - break; - // WEEKDAY - human - case 'dd': - case 'ddd': - case 'dddd': - a = config._locale.weekdaysParse(input); - // if we didn't get a weekday name, mark the date as invalid - if (a != null) { - config._w = config._w || {}; - config._w['d'] = a; - } else { - config._pf.invalidWeekday = input; - } - break; - // WEEK, WEEK DAY - numeric - case 'w': - case 'ww': - case 'W': - case 'WW': - case 'd': - case 'e': - case 'E': - token = token.substr(0, 1); - /* falls through */ - case 'gggg': - case 'GGGG': - case 'GGGGG': - token = token.substr(0, 2); - if (input) { - config._w = config._w || {}; - config._w[token] = toInt(input); - } - break; - case 'gg': - case 'GG': - config._w = config._w || {}; - config._w[token] = moment.parseTwoDigitYear(input); - } - } - - function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp; - - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - dow = 1; - doy = 4; - - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). - weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); - week = dfl(w.W, 1); - weekday = dfl(w.E, 1); - } else { - dow = config._locale._week.dow; - doy = config._locale._week.doy; - - weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); - week = dfl(w.w, 1); - - if (w.d != null) { - // weekday -- low day numbers are considered next week - weekday = w.d; - if (weekday < dow) { - ++week; - } - } else if (w.e != null) { - // local weekday -- counting starts from begining of week - weekday = w.e + dow; - } else { - // default to begining of week - weekday = dow; - } - } - temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); - - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromConfig(config) { - var i, date, input = [], currentDate, yearToUse; - - if (config._d) { - return; - } - - currentDate = currentDateArray(config); - - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - dayOfYearFromWeekInfo(config); - } - - //if the day of the year is set, figure out what it is - if (config._dayOfYear) { - yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); - - if (config._dayOfYear > daysInYear(yearToUse)) { - config._pf._overflowDayOfYear = true; - } - - date = makeUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } - - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } - - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } - - config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); - // Apply timezone offset from input. The actual zone can be changed - // with parseZone. - if (config._tzm != null) { - config._d.setUTCMinutes(config._d.getUTCMinutes() + config._tzm); - } - } - - function dateFromObject(config) { - var normalizedInput; - - if (config._d) { - return; - } - - normalizedInput = normalizeObjectUnits(config._i); - config._a = [ - normalizedInput.year, - normalizedInput.month, - normalizedInput.day, - normalizedInput.hour, - normalizedInput.minute, - normalizedInput.second, - normalizedInput.millisecond - ]; - - dateFromConfig(config); - } - - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; - } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; - } - } - - // date from string and format string - function makeDateFromStringAndFormat(config) { - if (config._f === moment.ISO_8601) { - parseISO(config); - return; - } - - config._a = []; - config._pf.empty = true; - - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; - - tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; - - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - config._pf.unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - config._pf.empty = false; - } - else { - config._pf.unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); - } - else if (config._strict && !parsedInput) { - config._pf.unusedTokens.push(token); - } - } - - // add remaining unparsed input length to the string - config._pf.charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - config._pf.unusedInput.push(string); - } - - // handle am pm - if (config._isPm && config._a[HOUR] < 12) { - config._a[HOUR] += 12; - } - // if is 12 am, change hours to 0 - if (config._isPm === false && config._a[HOUR] === 12) { - config._a[HOUR] = 0; - } - - dateFromConfig(config); - checkOverflow(config); - } - - function unescapeFormat(s) { - return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - }); - } - - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function regexpEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } - - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - bestMoment, - - scoreToBeat, - i, - currentScore; - - if (config._f.length === 0) { - config._pf.invalidFormat = true; - config._d = new Date(NaN); - return; - } - - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = copyConfig({}, config); - tempConfig._pf = defaultParsingFlags(); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); - - if (!isValid(tempConfig)) { - continue; - } - - // if there is any input that was not parsed add a penalty for that format - currentScore += tempConfig._pf.charsLeftOver; - - //or tokens - currentScore += tempConfig._pf.unusedTokens.length * 10; - - tempConfig._pf.score = currentScore; - - if (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - } - } - - extend(config, bestMoment || tempConfig); - } - - // date from iso format - function parseISO(config) { - var i, l, - string = config._i, - match = isoRegex.exec(string); - - if (match) { - config._pf.iso = true; - for (i = 0, l = isoDates.length; i < l; i++) { - if (isoDates[i][1].exec(string)) { - // match[5] should be "T" or undefined - config._f = isoDates[i][0] + (match[6] || ' '); - break; - } - } - for (i = 0, l = isoTimes.length; i < l; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (string.match(parseTokenTimezone)) { - config._f += 'Z'; - } - makeDateFromStringAndFormat(config); - } else { - config._isValid = false; - } - } - - // date from iso format or fallback - function makeDateFromString(config) { - parseISO(config); - if (config._isValid === false) { - delete config._isValid; - moment.createFromInputFallback(config); - } - } - - function makeDateFromInput(config) { - var input = config._i, matched; - if (input === undefined) { - config._d = new Date(); - } else if (isDate(input)) { - config._d = new Date(+input); - } else if ((matched = aspNetJsonRegex.exec(input)) !== null) { - config._d = new Date(+matched[1]); - } else if (typeof input === 'string') { - makeDateFromString(config); - } else if (isArray(input)) { - config._a = input.slice(0); - dateFromConfig(config); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else if (typeof(input) === 'number') { - // from milliseconds - config._d = new Date(input); - } else { - moment.createFromInputFallback(config); - } - } - - function makeDate(y, m, d, h, M, s, ms) { - //can't just apply() to create a date: - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); - - //the date constructor doesn't accept years < 1970 - if (y < 1970) { - date.setFullYear(y); - } - return date; - } - - function makeUTCDate(y) { - var date = new Date(Date.UTC.apply(null, arguments)); - if (y < 1970) { - date.setUTCFullYear(y); - } - return date; - } - - function parseWeekday(input, locale) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = locale.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } - } - return input; - } - - /************************************ - Relative Time - ************************************/ - - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - - function relativeTime(posNegDuration, withoutSuffix, locale) { - var duration = moment.duration(posNegDuration).abs(), - seconds = round(duration.as('s')), - minutes = round(duration.as('m')), - hours = round(duration.as('h')), - days = round(duration.as('d')), - months = round(duration.as('M')), - years = round(duration.as('y')), - - args = seconds < relativeTimeThresholds.s && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < relativeTimeThresholds.m && ['mm', minutes] || - hours === 1 && ['h'] || - hours < relativeTimeThresholds.h && ['hh', hours] || - days === 1 && ['d'] || - days < relativeTimeThresholds.d && ['dd', days] || - months === 1 && ['M'] || - months < relativeTimeThresholds.M && ['MM', months] || - years === 1 && ['y'] || ['yy', years]; - - args[2] = withoutSuffix; - args[3] = +posNegDuration > 0; - args[4] = locale; - return substituteTimeAgo.apply({}, args); - } - - - /************************************ - Week of Year - ************************************/ - - - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; - - - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } - - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } - - adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } - - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; - - d = d === 0 ? 7 : d; - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; - - return { - year: dayOfYear > 0 ? year : year - 1, - dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear - }; - } - - /************************************ - Top Level Functions - ************************************/ - - function makeMoment(config) { - var input = config._i, - format = config._f; - - config._locale = config._locale || moment.localeData(config._l); - - if (input === null || (format === undefined && input === '')) { - return moment.invalid({nullInput: true}); - } - - if (typeof input === 'string') { - config._i = input = config._locale.preparse(input); - } - - if (moment.isMoment(input)) { - return new Moment(input, true); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); - } - } else { - makeDateFromInput(config); - } - - return new Moment(config); - } - - moment = function (input, format, locale, strict) { - var c; - - if (typeof(locale) === "boolean") { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._i = input; - c._f = format; - c._l = locale; - c._strict = strict; - c._isUTC = false; - c._pf = defaultParsingFlags(); - - return makeMoment(c); - }; - - moment.suppressDeprecationWarnings = false; - - moment.createFromInputFallback = deprecate( - 'moment construction falls back to js Date. This is ' + - 'discouraged and will be removed in upcoming major ' + - 'release. Please refer to ' + - 'https://github.com/moment/moment/issues/1407 for more info.', - function (config) { - config._d = new Date(config._i); - } - ); - - // Pick a moment m from moments so that m[fn](other) is true for all - // other. This relies on the function fn to be transitive. - // - // moments should either be an array of moment objects or an array, whose - // first element is an array of moment objects. - function pickBy(fn, moments) { - var res, i; - if (moments.length === 1 && isArray(moments[0])) { - moments = moments[0]; - } - if (!moments.length) { - return moment(); - } - res = moments[0]; - for (i = 1; i < moments.length; ++i) { - if (moments[i][fn](res)) { - res = moments[i]; - } - } - return res; - } - - moment.min = function () { - var args = [].slice.call(arguments, 0); - - return pickBy('isBefore', args); - }; - - moment.max = function () { - var args = [].slice.call(arguments, 0); - - return pickBy('isAfter', args); - }; - - // creating with utc - moment.utc = function (input, format, locale, strict) { - var c; - - if (typeof(locale) === "boolean") { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._useUTC = true; - c._isUTC = true; - c._l = locale; - c._i = input; - c._f = format; - c._strict = strict; - c._pf = defaultParsingFlags(); - - return makeMoment(c).utc(); - }; - - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; - - // duration - moment.duration = function (input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - parseIso, - diffRes; - - if (moment.isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months - }; - } else if (typeof input === 'number') { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(match[MILLISECOND]) * sign - }; - } else if (!!(match = isoDurationRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - parseIso = function (inp) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - }; - duration = { - y: parseIso(match[2]), - M: parseIso(match[3]), - d: parseIso(match[4]), - h: parseIso(match[5]), - m: parseIso(match[6]), - s: parseIso(match[7]), - w: parseIso(match[8]) - }; - } else if (typeof duration === 'object' && - ('from' in duration || 'to' in duration)) { - diffRes = momentsDifference(moment(duration.from), moment(duration.to)); - - duration = {}; - duration.ms = diffRes.milliseconds; - duration.M = diffRes.months; - } - - ret = new Duration(duration); - - if (moment.isDuration(input) && input.hasOwnProperty('_locale')) { - ret._locale = input._locale; - } - - return ret; - }; - - // version number - moment.version = VERSION; - - // default format - moment.defaultFormat = isoFormat; - - // constant that refers to the ISO standard - moment.ISO_8601 = function () {}; - - // Plugins that add properties should also add the key here (null value), - // so we can properly clone ourselves. - moment.momentProperties = momentProperties; - - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - moment.updateOffset = function () {}; - - // This function allows you to set a threshold for relative time strings - moment.relativeTimeThreshold = function (threshold, limit) { - if (relativeTimeThresholds[threshold] === undefined) { - return false; - } - if (limit === undefined) { - return relativeTimeThresholds[threshold]; - } - relativeTimeThresholds[threshold] = limit; - return true; - }; - - moment.lang = deprecate( - "moment.lang is deprecated. Use moment.locale instead.", - function (key, value) { - return moment.locale(key, value); - } - ); - - // This function will load locale and then set the global locale. If - // no arguments are passed in, it will simply return the current global - // locale key. - moment.locale = function (key, values) { - var data; - if (key) { - if (typeof(values) !== "undefined") { - data = moment.defineLocale(key, values); - } - else { - data = moment.localeData(key); - } - - if (data) { - moment.duration._locale = moment._locale = data; - } - } - - return moment._locale._abbr; - }; - - moment.defineLocale = function (name, values) { - if (values !== null) { - values.abbr = name; - if (!locales[name]) { - locales[name] = new Locale(); - } - locales[name].set(values); - - // backwards compat for now: also set the locale - moment.locale(name); - - return locales[name]; - } else { - // useful for testing - delete locales[name]; - return null; - } - }; - - moment.langData = deprecate( - "moment.langData is deprecated. Use moment.localeData instead.", - function (key) { - return moment.localeData(key); - } - ); - - // returns locale data - moment.localeData = function (key) { - var locale; - - if (key && key._locale && key._locale._abbr) { - key = key._locale._abbr; - } - - if (!key) { - return moment._locale; - } - - if (!isArray(key)) { - //short-circuit everything else - locale = loadLocale(key); - if (locale) { - return locale; - } - key = [key]; - } - - return chooseLocale(key); - }; - - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment || - (obj != null && obj.hasOwnProperty('_isAMomentObject')); - }; - - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; - - for (i = lists.length - 1; i >= 0; --i) { - makeList(lists[i]); - } - - moment.normalizeUnits = function (units) { - return normalizeUnits(units); - }; - - moment.invalid = function (flags) { - var m = moment.utc(NaN); - if (flags != null) { - extend(m._pf, flags); - } - else { - m._pf.userInvalidated = true; - } - - return m; - }; - - moment.parseZone = function () { - return moment.apply(null, arguments).parseZone(); - }; - - moment.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; - - /************************************ - Moment Prototype - ************************************/ - - - extend(moment.fn = Moment.prototype, { - - clone : function () { - return moment(this); - }, - - valueOf : function () { - return +this._d + ((this._offset || 0) * 60000); - }, - - unix : function () { - return Math.floor(+this / 1000); - }, - - toString : function () { - return this.clone().locale('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); - }, - - toDate : function () { - return this._offset ? new Date(+this) : this._d; - }, - - toISOString : function () { - var m = moment(this).utc(); - if (0 < m.year() && m.year() <= 9999) { - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } else { - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - }, - - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, - - isValid : function () { - return isValid(this); - }, - - isDSTShifted : function () { - if (this._a) { - return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; - } - - return false; - }, - - parsingFlags : function () { - return extend({}, this._pf); - }, - - invalidAt: function () { - return this._pf.overflow; - }, - - utc : function (keepLocalTime) { - return this.zone(0, keepLocalTime); - }, - - local : function (keepLocalTime) { - if (this._isUTC) { - this.zone(0, keepLocalTime); - this._isUTC = false; - - if (keepLocalTime) { - this.add(this._d.getTimezoneOffset(), 'm'); - } - } - return this; - }, - - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.localeData().postformat(output); - }, - - add : createAdder(1, 'add'), - - subtract : createAdder(-1, 'subtract'), - - diff : function (input, units, asFloat) { - var that = makeAs(input, this), - zoneDiff = (this.zone() - that.zone()) * 6e4, - diff, output; - - units = normalizeUnits(units); - - if (units === 'year' || units === 'month') { - // average number of days in the months in the given dates - diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 - // difference in months - output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); - // adjust by taking difference in days, average number of days - // and dst in the given months. - output += ((this - moment(this).startOf('month')) - - (that - moment(that).startOf('month'))) / diff; - // same as above but with zones, to negate all dst - output -= ((this.zone() - moment(this).startOf('month').zone()) - - (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; - if (units === 'year') { - output = output / 12; - } - } else { - diff = (this - that); - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; - } - return asFloat ? output : absRound(output); - }, - - from : function (time, withoutSuffix) { - return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); - }, - - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, - - calendar : function (time) { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're zone'd or not. - var now = time || moment(), - sod = makeAs(now, this).startOf('day'), - diff = this.diff(sod, 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.localeData().calendar(format, this)); - }, - - isLeapYear : function () { - return isLeapYear(this.year()); - }, - - isDST : function () { - return (this.zone() < this.clone().month(0).zone() || - this.zone() < this.clone().month(5).zone()); - }, - - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.localeData()); - return this.add(input - day, 'd'); - } else { - return day; - } - }, - - month : makeAccessor('Month', true), - - startOf : function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'quarter': - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } - - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoWeek') { - this.isoWeekday(1); - } - - // quarters are also special - if (units === 'quarter') { - this.month(Math.floor(this.month() / 3) * 3); - } - - return this; - }, - - endOf: function (units) { - units = normalizeUnits(units); - return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); - }, - - isAfter: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) > +moment(input).startOf(units); - }, - - isBefore: function (input, units) { - units = typeof units !== 'undefined' ? units : 'millisecond'; - return +this.clone().startOf(units) < +moment(input).startOf(units); - }, - - isSame: function (input, units) { - units = units || 'ms'; - return +this.clone().startOf(units) === +makeAs(input, this).startOf(units); - }, - - min: deprecate( - 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', - function (other) { - other = moment.apply(null, arguments); - return other < this ? this : other; - } - ), - - max: deprecate( - 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', - function (other) { - other = moment.apply(null, arguments); - return other > this ? this : other; - } - ), - - // keepLocalTime = true means only change the timezone, without - // affecting the local hour. So 5:31:26 +0300 --[zone(2, true)]--> - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist int zone - // +0200, so we adjust the time as needed, to be valid. - // - // Keeping the time actually adds/subtracts (one hour) - // from the actual represented time. That is why we call updateOffset - // a second time. In case it wants us to change the offset again - // _changeInProgress == true case, then we have to adjust, because - // there is no such time in the given timezone. - zone : function (input, keepLocalTime) { - var offset = this._offset || 0, - localAdjust; - if (input != null) { - if (typeof input === 'string') { - input = timezoneMinutesFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - if (!this._isUTC && keepLocalTime) { - localAdjust = this._d.getTimezoneOffset(); - } - this._offset = input; - this._isUTC = true; - if (localAdjust != null) { - this.subtract(localAdjust, 'm'); - } - if (offset !== input) { - if (!keepLocalTime || this._changeInProgress) { - addOrSubtractDurationFromMoment(this, - moment.duration(offset - input, 'm'), 1, false); - } else if (!this._changeInProgress) { - this._changeInProgress = true; - moment.updateOffset(this, true); - this._changeInProgress = null; - } - } - } else { - return this._isUTC ? offset : this._d.getTimezoneOffset(); - } - return this; - }, - - zoneAbbr : function () { - return this._isUTC ? 'UTC' : ''; - }, - - zoneName : function () { - return this._isUTC ? 'Coordinated Universal Time' : ''; - }, - - parseZone : function () { - if (this._tzm) { - this.zone(this._tzm); - } else if (typeof this._i === 'string') { - this.zone(this._i); - } - return this; - }, - - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; - } - else { - input = moment(input).zone(); - } - - return (this.zone() - input) % 60 === 0; - }, - - daysInMonth : function () { - return daysInMonth(this.year(), this.month()); - }, - - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); - }, - - quarter : function (input) { - return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); - }, - - weekYear : function (input) { - var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; - return input == null ? year : this.add((input - year), 'y'); - }, - - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add((input - year), 'y'); - }, - - week : function (input) { - var week = this.localeData().week(this); - return input == null ? week : this.add((input - week) * 7, 'd'); - }, - - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add((input - week) * 7, 'd'); - }, - - weekday : function (input) { - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; - return input == null ? weekday : this.add(input - weekday, 'd'); - }, - - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, - - isoWeeksInYear : function () { - return weeksInYear(this.year(), 1, 4); - }, - - weeksInYear : function () { - var weekInfo = this.localeData()._week; - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units](); - }, - - set : function (units, value) { - units = normalizeUnits(units); - if (typeof this[units] === 'function') { - this[units](value); - } - return this; - }, - - // If passed a locale key, it will set the locale for this - // instance. Otherwise, it will return the locale configuration - // variables for this instance. - locale : function (key) { - if (key === undefined) { - return this._locale._abbr; - } else { - this._locale = moment.localeData(key); - return this; - } - }, - - lang : deprecate( - "moment().lang() is deprecated. Use moment().localeData() instead.", - function (key) { - if (key === undefined) { - return this.localeData(); - } else { - this._locale = moment.localeData(key); - return this; - } - } - ), - - localeData : function () { - return this._locale; - } - }); - - function rawMonthSetter(mom, value) { - var dayOfMonth; - - // TODO: Move this out of here! - if (typeof value === 'string') { - value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? - if (typeof value !== 'number') { - return mom; - } - } - - dayOfMonth = Math.min(mom.date(), - daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); - return mom; - } - - function rawGetter(mom, unit) { - return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); - } - - function rawSetter(mom, unit, value) { - if (unit === 'Month') { - return rawMonthSetter(mom, value); - } else { - return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } - } - - function makeAccessor(unit, keepTime) { - return function (value) { - if (value != null) { - rawSetter(this, unit, value); - moment.updateOffset(this, keepTime); - return this; - } else { - return rawGetter(this, unit); - } - }; - } - - moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); - moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); - moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); - // Setting the hour should keep the time, because the user explicitly - // specified which hour he wants. So trying to maintain the same hour (in - // a new timezone) makes sense. Adding/subtracting hours does not follow - // this rule. - moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true); - // moment.fn.month is defined separately - moment.fn.date = makeAccessor('Date', true); - moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true)); - moment.fn.year = makeAccessor('FullYear', true); - moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); - - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; - moment.fn.quarters = moment.fn.quarter; - - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; - - /************************************ - Duration Prototype - ************************************/ - - - function daysToYears (days) { - // 400 years have 146097 days (taking into account leap year rules) - return days * 400 / 146097; - } - - function yearsToDays (years) { - // years * 365 + absRound(years / 4) - - // absRound(years / 100) + absRound(years / 400); - return years * 146097 / 400; - } - - extend(moment.duration.fn = Duration.prototype, { - - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years = 0; - - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; - - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; - - hours = absRound(minutes / 60); - data.hours = hours % 24; - - days += absRound(hours / 24); - - // Accurately convert days to years, assume start from year 0. - years = absRound(daysToYears(days)); - days -= absRound(yearsToDays(years)); - - // 30 days to a month - // TODO (iskren): Use anchor date (like 1st Jan) to compute this. - months += absRound(days / 30); - days %= 30; - - // 12 months -> 1 year - years += absRound(months / 12); - months %= 12; - - data.days = days; - data.months = months; - data.years = years; - }, - - abs : function () { - this._milliseconds = Math.abs(this._milliseconds); - this._days = Math.abs(this._days); - this._months = Math.abs(this._months); - - this._data.milliseconds = Math.abs(this._data.milliseconds); - this._data.seconds = Math.abs(this._data.seconds); - this._data.minutes = Math.abs(this._data.minutes); - this._data.hours = Math.abs(this._data.hours); - this._data.months = Math.abs(this._data.months); - this._data.years = Math.abs(this._data.years); - - return this; - }, - - weeks : function () { - return absRound(this.days() / 7); - }, - - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6; - }, - - humanize : function (withSuffix) { - var output = relativeTime(this, !withSuffix, this.localeData()); - - if (withSuffix) { - output = this.localeData().pastFuture(+this, output); - } - - return this.localeData().postformat(output); - }, - - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); - - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; - - this._bubble(); - - return this; - }, - - subtract : function (input, val) { - var dur = moment.duration(input, val); - - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; - - this._bubble(); - - return this; - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, - - as : function (units) { - var days, months; - units = normalizeUnits(units); - - days = this._days + this._milliseconds / 864e5; - if (units === 'month' || units === 'year') { - months = this._months + daysToYears(days) * 12; - return units === 'month' ? months : months / 12; - } else { - days += yearsToDays(this._months / 12); - switch (units) { - case 'week': return days / 7; - case 'day': return days; - case 'hour': return days * 24; - case 'minute': return days * 24 * 60; - case 'second': return days * 24 * 60 * 60; - case 'millisecond': return days * 24 * 60 * 60 * 1000; - default: throw new Error('Unknown unit ' + units); - } - } - }, - - lang : moment.fn.lang, - locale : moment.fn.locale, - - toIsoString : deprecate( - "toIsoString() is deprecated. Please use toISOString() instead " + - "(notice the capitals)", - function () { - return this.toISOString(); - } - ), - - toISOString : function () { - // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js - var years = Math.abs(this.years()), - months = Math.abs(this.months()), - days = Math.abs(this.days()), - hours = Math.abs(this.hours()), - minutes = Math.abs(this.minutes()), - seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); - - if (!this.asSeconds()) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } - - return (this.asSeconds() < 0 ? '-' : '') + - 'P' + - (years ? years + 'Y' : '') + - (months ? months + 'M' : '') + - (days ? days + 'D' : '') + - ((hours || minutes || seconds) ? 'T' : '') + - (hours ? hours + 'H' : '') + - (minutes ? minutes + 'M' : '') + - (seconds ? seconds + 'S' : ''); - }, - - localeData : function () { - return this._locale; - } - }); - - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; - } - - for (i in unitMillisecondFactors) { - if (unitMillisecondFactors.hasOwnProperty(i)) { - makeDurationGetter(i.toLowerCase()); - } - } - - moment.duration.fn.asMilliseconds = function () { - return this.as('ms'); - }; - moment.duration.fn.asSeconds = function () { - return this.as('s'); - }; - moment.duration.fn.asMinutes = function () { - return this.as('m'); - }; - moment.duration.fn.asHours = function () { - return this.as('h'); - }; - moment.duration.fn.asDays = function () { - return this.as('d'); - }; - moment.duration.fn.asWeeks = function () { - return this.as('weeks'); - }; - moment.duration.fn.asMonths = function () { - return this.as('M'); - }; - moment.duration.fn.asYears = function () { - return this.as('y'); - }; - - /************************************ - Default Locale - ************************************/ - - - // Set default locale, other locale will inherit from English. - moment.locale('en', { - ordinal : function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); - - /* EMBED_LOCALES */ - - /************************************ - Exposing Moment - ************************************/ - - function makeGlobal(shouldDeprecate) { - /*global ender:false */ - if (typeof ender !== 'undefined') { - return; - } - oldGlobalMoment = globalScope.moment; - if (shouldDeprecate) { - globalScope.moment = deprecate( - 'Accessing Moment through the global scope is ' + - 'deprecated, and will be removed in an upcoming ' + - 'release.', - moment); - } else { - globalScope.moment = moment; - } - } - - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - } else if (typeof define === 'function' && define.amd) { - define('moment', function (require, exports, module) { - if (module.config && module.config() && module.config().noGlobal === true) { - // release the global variable - globalScope.moment = oldGlobalMoment; - } - - return moment; - }); - makeGlobal(true); - } else { - makeGlobal(); - } +//! moment.js +//! version : 2.8.1 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +(function (undefined) { + /************************************ + Constants + ************************************/ + + var moment, + VERSION = '2.8.1', + // the global-scope this is NOT the global object in Node.js + globalScope = typeof global !== 'undefined' ? global : this, + oldGlobalMoment, + round = Math.round, + i, + + YEAR = 0, + MONTH = 1, + DATE = 2, + HOUR = 3, + MINUTE = 4, + SECOND = 5, + MILLISECOND = 6, + + // internal storage for locale config files + locales = {}, + + // extra moment internal properties (plugins register props here) + momentProperties = [], + + // check for nodeJS + hasModule = (typeof module !== 'undefined' && module.exports), + + // ASP.NET json date format regex + aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, + aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, + + // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html + // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere + isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, + + // format tokens + formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g, + localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, + + // parsing token regexes + parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 + parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 + parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 + parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 + parseTokenDigits = /\d+/, // nonzero number of digits + parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. + parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z + parseTokenT = /T/i, // T (ISO separator) + parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 + parseTokenOrdinal = /\d{1,2}/, + + //strict parsing regexes + parseTokenOneDigit = /\d/, // 0 - 9 + parseTokenTwoDigits = /\d\d/, // 00 - 99 + parseTokenThreeDigits = /\d{3}/, // 000 - 999 + parseTokenFourDigits = /\d{4}/, // 0000 - 9999 + parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 + parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf + + // iso 8601 regex + // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) + isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, + + isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', + + isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], + ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], + ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], + ['GGGG-[W]WW', /\d{4}-W\d{2}/], + ['YYYY-DDD', /\d{4}-\d{3}/] + ], + + // iso time formats and regexes + isoTimes = [ + ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], + ['HH:mm', /(T| )\d\d:\d\d/], + ['HH', /(T| )\d\d/] + ], + + // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"] + parseTimezoneChunker = /([\+\-]|\d\d)/gi, + + // getter and setter names + proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), + unitMillisecondFactors = { + 'Milliseconds' : 1, + 'Seconds' : 1e3, + 'Minutes' : 6e4, + 'Hours' : 36e5, + 'Days' : 864e5, + 'Months' : 2592e6, + 'Years' : 31536e6 + }, + + unitAliases = { + ms : 'millisecond', + s : 'second', + m : 'minute', + h : 'hour', + d : 'day', + D : 'date', + w : 'week', + W : 'isoWeek', + M : 'month', + Q : 'quarter', + y : 'year', + DDD : 'dayOfYear', + e : 'weekday', + E : 'isoWeekday', + gg: 'weekYear', + GG: 'isoWeekYear' + }, + + camelFunctions = { + dayofyear : 'dayOfYear', + isoweekday : 'isoWeekday', + isoweek : 'isoWeek', + weekyear : 'weekYear', + isoweekyear : 'isoWeekYear' + }, + + // format function strings + formatFunctions = {}, + + // default relative time thresholds + relativeTimeThresholds = { + s: 45, // seconds to minute + m: 45, // minutes to hour + h: 22, // hours to day + d: 26, // days to month + M: 11 // months to year + }, + + // tokens to ordinalize and pad + ordinalizeTokens = 'DDD w W M D d'.split(' '), + paddedTokens = 'M D H h m s w W'.split(' '), + + formatTokenFunctions = { + M : function () { + return this.month() + 1; + }, + MMM : function (format) { + return this.localeData().monthsShort(this, format); + }, + MMMM : function (format) { + return this.localeData().months(this, format); + }, + D : function () { + return this.date(); + }, + DDD : function () { + return this.dayOfYear(); + }, + d : function () { + return this.day(); + }, + dd : function (format) { + return this.localeData().weekdaysMin(this, format); + }, + ddd : function (format) { + return this.localeData().weekdaysShort(this, format); + }, + dddd : function (format) { + return this.localeData().weekdays(this, format); + }, + w : function () { + return this.week(); + }, + W : function () { + return this.isoWeek(); + }, + YY : function () { + return leftZeroFill(this.year() % 100, 2); + }, + YYYY : function () { + return leftZeroFill(this.year(), 4); + }, + YYYYY : function () { + return leftZeroFill(this.year(), 5); + }, + YYYYYY : function () { + var y = this.year(), sign = y >= 0 ? '+' : '-'; + return sign + leftZeroFill(Math.abs(y), 6); + }, + gg : function () { + return leftZeroFill(this.weekYear() % 100, 2); + }, + gggg : function () { + return leftZeroFill(this.weekYear(), 4); + }, + ggggg : function () { + return leftZeroFill(this.weekYear(), 5); + }, + GG : function () { + return leftZeroFill(this.isoWeekYear() % 100, 2); + }, + GGGG : function () { + return leftZeroFill(this.isoWeekYear(), 4); + }, + GGGGG : function () { + return leftZeroFill(this.isoWeekYear(), 5); + }, + e : function () { + return this.weekday(); + }, + E : function () { + return this.isoWeekday(); + }, + a : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), true); + }, + A : function () { + return this.localeData().meridiem(this.hours(), this.minutes(), false); + }, + H : function () { + return this.hours(); + }, + h : function () { + return this.hours() % 12 || 12; + }, + m : function () { + return this.minutes(); + }, + s : function () { + return this.seconds(); + }, + S : function () { + return toInt(this.milliseconds() / 100); + }, + SS : function () { + return leftZeroFill(toInt(this.milliseconds() / 10), 2); + }, + SSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + SSSS : function () { + return leftZeroFill(this.milliseconds(), 3); + }, + Z : function () { + var a = -this.zone(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); + }, + ZZ : function () { + var a = -this.zone(), + b = '+'; + if (a < 0) { + a = -a; + b = '-'; + } + return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); + }, + z : function () { + return this.zoneAbbr(); + }, + zz : function () { + return this.zoneName(); + }, + X : function () { + return this.unix(); + }, + Q : function () { + return this.quarter(); + } + }, + + deprecations = {}, + + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; + + // Pick the first defined of two or three arguments. dfl comes from + // default. + function dfl(a, b, c) { + switch (arguments.length) { + case 2: return a != null ? a : b; + case 3: return a != null ? a : b != null ? b : c; + default: throw new Error('Implement me'); + } + } + + function defaultParsingFlags() { + // We need to deep clone this object, and es5 standard is not very + // helpful. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso: false + }; + } + + function printMsg(msg) { + if (moment.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && console.warn) { + console.warn("Deprecation warning: " + msg); + } + } + + function deprecate(msg, fn) { + var firstTime = true; + return extend(function () { + if (firstTime) { + printMsg(msg); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); + } + + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + printMsg(msg); + deprecations[name] = true; + } + } + + function padToken(func, count) { + return function (a) { + return leftZeroFill(func.call(this, a), count); + }; + } + function ordinalizeToken(func, period) { + return function (a) { + return this.localeData().ordinal(func.call(this, a), period); + }; + } + + while (ordinalizeTokens.length) { + i = ordinalizeTokens.pop(); + formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); + } + while (paddedTokens.length) { + i = paddedTokens.pop(); + formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); + } + formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); + + + /************************************ + Constructors + ************************************/ + + function Locale() { + } + + // Moment prototype object + function Moment(config, skipOverflow) { + if (skipOverflow !== false) { + checkOverflow(config); + } + copyConfig(this, config); + this._d = new Date(+config._d); + } + + // Duration Constructor + function Duration(duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 36e5; // 1000 * 60 * 60 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; + + this._data = {}; + + this._locale = moment.localeData(); + + this._bubble(); + } + + /************************************ + Helpers + ************************************/ + + + function extend(a, b) { + for (var i in b) { + if (b.hasOwnProperty(i)) { + a[i] = b[i]; + } + } + + if (b.hasOwnProperty('toString')) { + a.toString = b.toString; + } + + if (b.hasOwnProperty('valueOf')) { + a.valueOf = b.valueOf; + } + + return a; + } + + function copyConfig(to, from) { + var i, prop, val; + + if (typeof from._isAMomentObject !== 'undefined') { + to._isAMomentObject = from._isAMomentObject; + } + if (typeof from._i !== 'undefined') { + to._i = from._i; + } + if (typeof from._f !== 'undefined') { + to._f = from._f; + } + if (typeof from._l !== 'undefined') { + to._l = from._l; + } + if (typeof from._strict !== 'undefined') { + to._strict = from._strict; + } + if (typeof from._tzm !== 'undefined') { + to._tzm = from._tzm; + } + if (typeof from._isUTC !== 'undefined') { + to._isUTC = from._isUTC; + } + if (typeof from._offset !== 'undefined') { + to._offset = from._offset; + } + if (typeof from._pf !== 'undefined') { + to._pf = from._pf; + } + if (typeof from._locale !== 'undefined') { + to._locale = from._locale; + } + + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (typeof val !== 'undefined') { + to[prop] = val; + } + } + } + + return to; + } + + function absRound(number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + + // left zero fill a number + // see http://jsperf.com/left-zero-filling for performance comparison + function leftZeroFill(number, targetLength, forceSign) { + var output = '' + Math.abs(number), + sign = number >= 0; + + while (output.length < targetLength) { + output = '0' + output; + } + return (sign ? (forceSign ? '+' : '') : '-') + output; + } + + function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; + + res.months = other.month() - base.month() + + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +(base.clone().add(res.months, 'M')); + + return res; + } + + function momentsDifference(base, other) { + var res; + other = makeAs(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; + } + + // TODO: remove 'name' arg after deprecation is removed + function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple(name, "moment()." + name + "(period, number) is deprecated. Please use moment()." + name + "(number, period)."); + tmp = val; val = period; period = tmp; + } + + val = typeof val === 'string' ? +val : val; + dur = moment.duration(val, period); + addOrSubtractDurationFromMoment(this, dur, direction); + return this; + }; + } + + function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = duration._days, + months = duration._months; + updateOffset = updateOffset == null ? true : updateOffset; + + if (milliseconds) { + mom._d.setTime(+mom._d + milliseconds * isAdding); + } + if (days) { + rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); + } + if (months) { + rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + moment.updateOffset(mom, days || months); + } + } + + // check if is an array + function isArray(input) { + return Object.prototype.toString.call(input) === '[object Array]'; + } + + function isDate(input) { + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; + } + + // compare two arrays, return the number of differences + function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; + } + + function normalizeUnits(units) { + if (units) { + var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); + units = unitAliases[units] || camelFunctions[lowered] || lowered; + } + return units; + } + + function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (inputObject.hasOwnProperty(prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; + } + + function makeList(field) { + var count, setter; + + if (field.indexOf('week') === 0) { + count = 7; + setter = 'day'; + } + else if (field.indexOf('month') === 0) { + count = 12; + setter = 'month'; + } + else { + return; + } + + moment[field] = function (format, index) { + var i, getter, + method = moment._locale[field], + results = []; + + if (typeof format === 'number') { + index = format; + format = undefined; + } + + getter = function (i) { + var m = moment().utc().set(setter, i); + return method.call(moment._locale, m, format || ''); + }; + + if (index != null) { + return getter(index); + } + else { + for (i = 0; i < count; i++) { + results.push(getter(i)); + } + return results; + } + }; + } + + function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + if (coercedNumber >= 0) { + value = Math.floor(coercedNumber); + } else { + value = Math.ceil(coercedNumber); + } + } + + return value; + } + + function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); + } + + function weeksInYear(year, dow, doy) { + return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; + } + + function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; + } + + function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; + } + + function checkOverflow(m) { + var overflow; + if (m._a && m._pf.overflow === -2) { + overflow = + m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : + m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : + m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR : + m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : + m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : + m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + + m._pf.overflow = overflow; + } + } + + function isValid(m) { + if (m._isValid == null) { + m._isValid = !isNaN(m._d.getTime()) && + m._pf.overflow < 0 && + !m._pf.empty && + !m._pf.invalidMonth && + !m._pf.nullInput && + !m._pf.invalidFormat && + !m._pf.userInvalidated; + + if (m._strict) { + m._isValid = m._isValid && + m._pf.charsLeftOver === 0 && + m._pf.unusedTokens.length === 0; + } + } + return m._isValid; + } + + function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; + } + + // pick the locale from the array + // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + function chooseLocale(names) { + var i = 0, j, next, locale, split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return null; + } + + function loadLocale(name) { + var oldLocale = null; + if (!locales[name] && hasModule) { + try { + oldLocale = moment.locale(); + require('./locale/' + name); + // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales + moment.locale(oldLocale); + } catch (e) { } + } + return locales[name]; + } + + // Return a moment from input, that is local/utc/zone equivalent to model. + function makeAs(input, model) { + return model._isUTC ? moment(input).zone(model._offset || 0) : + moment(input).local(); + } + + /************************************ + Locale + ************************************/ + + + extend(Locale.prototype, { + + set : function (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (typeof prop === 'function') { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + }, + + _months : '1_2_3_4_May_June_July_August_September_October_November_December'.split('_'), + months : function (m) { + return this._months[m.month()]; + }, + + _monthsShort : '1_2_3_4_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), + monthsShort : function (m) { + return this._monthsShort[m.month()]; + }, + + monthsParse : function (monthName) { + var i, mom, regex; + + if (!this._monthsParse) { + this._monthsParse = []; + } + + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + if (!this._monthsParse[i]) { + mom = moment.utc([2000, i]); + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._monthsParse[i].test(monthName)) { + return i; + } + } + }, + + _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), + weekdays : function (m) { + return this._weekdays[m.day()]; + }, + + _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), + weekdaysShort : function (m) { + return this._weekdaysShort[m.day()]; + }, + + _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), + weekdaysMin : function (m) { + return this._weekdaysMin[m.day()]; + }, + + weekdaysParse : function (weekdayName) { + var i, mom, regex; + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + if (!this._weekdaysParse[i]) { + mom = moment([2000, 1]).day(i); + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } + }, + + _longDateFormat : { + LT : 'h:mm A', + L : 'MM/DD/YYYY', + LL : 'MMMM D, YYYY', + LLL : 'MMMM D, YYYY LT', + LLLL : 'dddd, MMMM D, YYYY LT' + }, + longDateFormat : function (key) { + var output = this._longDateFormat[key]; + if (!output && this._longDateFormat[key.toUpperCase()]) { + output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + this._longDateFormat[key] = output; + } + return output; + }, + + isPM : function (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); + }, + + _meridiemParse : /[ap]\.?m?\.?/i, + meridiem : function (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } + }, + + _calendar : { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' + }, + calendar : function (key, mom) { + var output = this._calendar[key]; + return typeof output === 'function' ? output.apply(mom) : output; + }, + + _relativeTime : { + future : 'in %s', + past : '%s ago', + s : 'a few seconds', + m : 'a minute', + mm : '%d minutes', + h : 'an hour', + hh : '%d hours', + d : 'a day', + dd : '%d days', + M : 'a month', + MM : '%d months', + y : 'a year', + yy : '%d years' + }, + + relativeTime : function (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (typeof output === 'function') ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); + }, + + pastFuture : function (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); + }, + + ordinal : function (number) { + return this._ordinal.replace('%d', number); + }, + _ordinal : '%d', + + preparse : function (string) { + return string; + }, + + postformat : function (string) { + return string; + }, + + week : function (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; + }, + + _week : { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. + }, + + _invalidDate: 'Invalid date', + invalidDate: function () { + return this._invalidDate; + } + }); + + /************************************ + Formatting + ************************************/ + + + function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); + } + + function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = ''; + for (i = 0; i < length; i++) { + output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; + } + return output; + }; + } + + // format date using native date object + function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + + format = expandFormat(format, m.localeData()); + + if (!formatFunctions[format]) { + formatFunctions[format] = makeFormatFunction(format); + } + + return formatFunctions[format](m); + } + + function expandFormat(format, locale) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; + } + + + /************************************ + Parsing + ************************************/ + + + // get the regex to find the next token + function getParseRegexForToken(token, config) { + var a, strict = config._strict; + switch (token) { + case 'Q': + return parseTokenOneDigit; + case 'DDDD': + return parseTokenThreeDigits; + case 'YYYY': + case 'GGGG': + case 'gggg': + return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; + case 'Y': + case 'G': + case 'g': + return parseTokenSignedNumber; + case 'YYYYYY': + case 'YYYYY': + case 'GGGGG': + case 'ggggg': + return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; + case 'S': + if (strict) { + return parseTokenOneDigit; + } + /* falls through */ + case 'SS': + if (strict) { + return parseTokenTwoDigits; + } + /* falls through */ + case 'SSS': + if (strict) { + return parseTokenThreeDigits; + } + /* falls through */ + case 'DDD': + return parseTokenOneToThreeDigits; + case 'MMM': + case 'MMMM': + case 'dd': + case 'ddd': + case 'dddd': + return parseTokenWord; + case 'a': + case 'A': + return config._locale._meridiemParse; + case 'X': + return parseTokenTimestampMs; + case 'Z': + case 'ZZ': + return parseTokenTimezone; + case 'T': + return parseTokenT; + case 'SSSS': + return parseTokenDigits; + case 'MM': + case 'DD': + case 'YY': + case 'GG': + case 'gg': + case 'HH': + case 'hh': + case 'mm': + case 'ss': + case 'ww': + case 'WW': + return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; + case 'M': + case 'D': + case 'd': + case 'H': + case 'h': + case 'm': + case 's': + case 'w': + case 'W': + case 'e': + case 'E': + return parseTokenOneOrTwoDigits; + case 'Do': + return parseTokenOrdinal; + default : + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); + return a; + } + } + + function timezoneMinutesFromString(string) { + string = string || ''; + var possibleTzMatches = (string.match(parseTokenTimezone) || []), + tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], + parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], + minutes = +(parts[1] * 60) + toInt(parts[2]); + + return parts[0] === '+' ? -minutes : minutes; + } + + // function to convert string input to date + function addTimeToArrayFromToken(token, input, config) { + var a, datePartArray = config._a; + + switch (token) { + // QUARTER + case 'Q': + if (input != null) { + datePartArray[MONTH] = (toInt(input) - 1) * 3; + } + break; + // MONTH + case 'M' : // fall through to MM + case 'MM' : + if (input != null) { + datePartArray[MONTH] = toInt(input) - 1; + } + break; + case 'MMM' : // fall through to MMMM + case 'MMMM' : + a = config._locale.monthsParse(input); + // if we didn't find a month name, mark the date as invalid. + if (a != null) { + datePartArray[MONTH] = a; + } else { + config._pf.invalidMonth = input; + } + break; + // DAY OF MONTH + case 'D' : // fall through to DD + case 'DD' : + if (input != null) { + datePartArray[DATE] = toInt(input); + } + break; + case 'Do' : + if (input != null) { + datePartArray[DATE] = toInt(parseInt(input, 10)); + } + break; + // DAY OF YEAR + case 'DDD' : // fall through to DDDD + case 'DDDD' : + if (input != null) { + config._dayOfYear = toInt(input); + } + + break; + // YEAR + case 'YY' : + datePartArray[YEAR] = moment.parseTwoDigitYear(input); + break; + case 'YYYY' : + case 'YYYYY' : + case 'YYYYYY' : + datePartArray[YEAR] = toInt(input); + break; + // AM / PM + case 'a' : // fall through to A + case 'A' : + config._isPm = config._locale.isPM(input); + break; + // 24 HOUR + case 'H' : // fall through to hh + case 'HH' : // fall through to hh + case 'h' : // fall through to hh + case 'hh' : + datePartArray[HOUR] = toInt(input); + break; + // MINUTE + case 'm' : // fall through to mm + case 'mm' : + datePartArray[MINUTE] = toInt(input); + break; + // SECOND + case 's' : // fall through to ss + case 'ss' : + datePartArray[SECOND] = toInt(input); + break; + // MILLISECOND + case 'S' : + case 'SS' : + case 'SSS' : + case 'SSSS' : + datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); + break; + // UNIX TIMESTAMP WITH MS + case 'X': + config._d = new Date(parseFloat(input) * 1000); + break; + // TIMEZONE + case 'Z' : // fall through to ZZ + case 'ZZ' : + config._useUTC = true; + config._tzm = timezoneMinutesFromString(input); + break; + // WEEKDAY - human + case 'dd': + case 'ddd': + case 'dddd': + a = config._locale.weekdaysParse(input); + // if we didn't get a weekday name, mark the date as invalid + if (a != null) { + config._w = config._w || {}; + config._w['d'] = a; + } else { + config._pf.invalidWeekday = input; + } + break; + // WEEK, WEEK DAY - numeric + case 'w': + case 'ww': + case 'W': + case 'WW': + case 'd': + case 'e': + case 'E': + token = token.substr(0, 1); + /* falls through */ + case 'gggg': + case 'GGGG': + case 'GGGGG': + token = token.substr(0, 2); + if (input) { + config._w = config._w || {}; + config._w[token] = toInt(input); + } + break; + case 'gg': + case 'GG': + config._w = config._w || {}; + config._w[token] = moment.parseTwoDigitYear(input); + } + } + + function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); + week = dfl(w.W, 1); + weekday = dfl(w.E, 1); + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; + + weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); + week = dfl(w.w, 1); + + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < dow) { + ++week; + } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; + } else { + // default to begining of week + weekday = dow; + } + } + temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); + + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } + + // convert an array to a date. + // the array should mirror the parameters below + // note: all values past the year are optional and will default to the lowest possible value. + // [year, month, day , hour, minute, second, millisecond] + function dateFromConfig(config) { + var i, date, input = [], currentDate, yearToUse; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear) { + yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); + + if (config._dayOfYear > daysInYear(yearToUse)) { + config._pf._overflowDayOfYear = true; + } + + date = makeUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); + // Apply timezone offset from input. The actual zone can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() + config._tzm); + } + } + + function dateFromObject(config) { + var normalizedInput; + + if (config._d) { + return; + } + + normalizedInput = normalizeObjectUnits(config._i); + config._a = [ + normalizedInput.year, + normalizedInput.month, + normalizedInput.day, + normalizedInput.hour, + normalizedInput.minute, + normalizedInput.second, + normalizedInput.millisecond + ]; + + dateFromConfig(config); + } + + function currentDateArray(config) { + var now = new Date(); + if (config._useUTC) { + return [ + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate() + ]; + } else { + return [now.getFullYear(), now.getMonth(), now.getDate()]; + } + } + + // date from string and format string + function makeDateFromStringAndFormat(config) { + if (config._f === moment.ISO_8601) { + parseISO(config); + return; + } + + config._a = []; + config._pf.empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + config._pf.unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + config._pf.empty = false; + } + else { + config._pf.unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + config._pf.unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + config._pf.charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + config._pf.unusedInput.push(string); + } + + // handle am pm + if (config._isPm && config._a[HOUR] < 12) { + config._a[HOUR] += 12; + } + // if is 12 am, change hours to 0 + if (config._isPm === false && config._a[HOUR] === 12) { + config._a[HOUR] = 0; + } + + dateFromConfig(config); + checkOverflow(config); + } + + function unescapeFormat(s) { + return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + }); + } + + // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + function regexpEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + + // date from string and array of format strings + function makeDateFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + config._pf.invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + tempConfig._pf = defaultParsingFlags(); + tempConfig._f = config._f[i]; + makeDateFromStringAndFormat(tempConfig); + + if (!isValid(tempConfig)) { + continue; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += tempConfig._pf.charsLeftOver; + + //or tokens + currentScore += tempConfig._pf.unusedTokens.length * 10; + + tempConfig._pf.score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + + extend(config, bestMoment || tempConfig); + } + + // date from iso format + function parseISO(config) { + var i, l, + string = config._i, + match = isoRegex.exec(string); + + if (match) { + config._pf.iso = true; + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(string)) { + // match[5] should be "T" or undefined + config._f = isoDates[i][0] + (match[6] || ' '); + break; + } + } + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(string)) { + config._f += isoTimes[i][0]; + break; + } + } + if (string.match(parseTokenTimezone)) { + config._f += 'Z'; + } + makeDateFromStringAndFormat(config); + } else { + config._isValid = false; + } + } + + // date from iso format or fallback + function makeDateFromString(config) { + parseISO(config); + if (config._isValid === false) { + delete config._isValid; + moment.createFromInputFallback(config); + } + } + + function makeDateFromInput(config) { + var input = config._i, matched; + if (input === undefined) { + config._d = new Date(); + } else if (isDate(input)) { + config._d = new Date(+input); + } else if ((matched = aspNetJsonRegex.exec(input)) !== null) { + config._d = new Date(+matched[1]); + } else if (typeof input === 'string') { + makeDateFromString(config); + } else if (isArray(input)) { + config._a = input.slice(0); + dateFromConfig(config); + } else if (typeof(input) === 'object') { + dateFromObject(config); + } else if (typeof(input) === 'number') { + // from milliseconds + config._d = new Date(input); + } else { + moment.createFromInputFallback(config); + } + } + + function makeDate(y, m, d, h, M, s, ms) { + //can't just apply() to create a date: + //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply + var date = new Date(y, m, d, h, M, s, ms); + + //the date constructor doesn't accept years < 1970 + if (y < 1970) { + date.setFullYear(y); + } + return date; + } + + function makeUTCDate(y) { + var date = new Date(Date.UTC.apply(null, arguments)); + if (y < 1970) { + date.setUTCFullYear(y); + } + return date; + } + + function parseWeekday(input, locale) { + if (typeof input === 'string') { + if (!isNaN(input)) { + input = parseInt(input, 10); + } + else { + input = locale.weekdaysParse(input); + if (typeof input !== 'number') { + return null; + } + } + } + return input; + } + + /************************************ + Relative Time + ************************************/ + + + // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + } + + function relativeTime(posNegDuration, withoutSuffix, locale) { + var duration = moment.duration(posNegDuration).abs(), + seconds = round(duration.as('s')), + minutes = round(duration.as('m')), + hours = round(duration.as('h')), + days = round(duration.as('d')), + months = round(duration.as('M')), + years = round(duration.as('y')), + + args = seconds < relativeTimeThresholds.s && ['s', seconds] || + minutes === 1 && ['m'] || + minutes < relativeTimeThresholds.m && ['mm', minutes] || + hours === 1 && ['h'] || + hours < relativeTimeThresholds.h && ['hh', hours] || + days === 1 && ['d'] || + days < relativeTimeThresholds.d && ['dd', days] || + months === 1 && ['M'] || + months < relativeTimeThresholds.M && ['MM', months] || + years === 1 && ['y'] || ['yy', years]; + + args[2] = withoutSuffix; + args[3] = +posNegDuration > 0; + args[4] = locale; + return substituteTimeAgo.apply({}, args); + } + + + /************************************ + Week of Year + ************************************/ + + + // firstDayOfWeek 0 = sun, 6 = sat + // the day of the week that starts the week + // (usually sunday or monday) + // firstDayOfWeekOfYear 0 = sun, 6 = sat + // the first week is the week that contains the first + // of this day of the week + // (eg. ISO weeks use thursday (4)) + function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { + var end = firstDayOfWeekOfYear - firstDayOfWeek, + daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), + adjustedMoment; + + + if (daysToDayOfWeek > end) { + daysToDayOfWeek -= 7; + } + + if (daysToDayOfWeek < end - 7) { + daysToDayOfWeek += 7; + } + + adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); + return { + week: Math.ceil(adjustedMoment.dayOfYear() / 7), + year: adjustedMoment.year() + }; + } + + //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday + function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { + var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; + + d = d === 0 ? 7 : d; + weekday = weekday != null ? weekday : firstDayOfWeek; + daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); + dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + + return { + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + }; + } + + /************************************ + Top Level Functions + ************************************/ + + function makeMoment(config) { + var input = config._i, + format = config._f; + + config._locale = config._locale || moment.localeData(config._l); + + if (input === null || (format === undefined && input === '')) { + return moment.invalid({nullInput: true}); + } + + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + + if (moment.isMoment(input)) { + return new Moment(input, true); + } else if (format) { + if (isArray(format)) { + makeDateFromStringAndArray(config); + } else { + makeDateFromStringAndFormat(config); + } + } else { + makeDateFromInput(config); + } + + return new Moment(config); + } + + moment = function (input, format, locale, strict) { + var c; + + if (typeof(locale) === "boolean") { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._i = input; + c._f = format; + c._l = locale; + c._strict = strict; + c._isUTC = false; + c._pf = defaultParsingFlags(); + + return makeMoment(c); + }; + + moment.suppressDeprecationWarnings = false; + + moment.createFromInputFallback = deprecate( + 'moment construction falls back to js Date. This is ' + + 'discouraged and will be removed in upcoming major ' + + 'release. Please refer to ' + + 'https://github.com/moment/moment/issues/1407 for more info.', + function (config) { + config._d = new Date(config._i); + } + ); + + // Pick a moment m from moments so that m[fn](other) is true for all + // other. This relies on the function fn to be transitive. + // + // moments should either be an array of moment objects or an array, whose + // first element is an array of moment objects. + function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return moment(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (moments[i][fn](res)) { + res = moments[i]; + } + } + return res; + } + + moment.min = function () { + var args = [].slice.call(arguments, 0); + + return pickBy('isBefore', args); + }; + + moment.max = function () { + var args = [].slice.call(arguments, 0); + + return pickBy('isAfter', args); + }; + + // creating with utc + moment.utc = function (input, format, locale, strict) { + var c; + + if (typeof(locale) === "boolean") { + strict = locale; + locale = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c = {}; + c._isAMomentObject = true; + c._useUTC = true; + c._isUTC = true; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + c._pf = defaultParsingFlags(); + + return makeMoment(c).utc(); + }; + + // creating with unix timestamp (in seconds) + moment.unix = function (input) { + return moment(input * 1000); + }; + + // duration + moment.duration = function (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + parseIso, + diffRes; + + if (moment.isDuration(input)) { + duration = { + ms: input._milliseconds, + d: input._days, + M: input._months + }; + } else if (typeof input === 'number') { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y: 0, + d: toInt(match[DATE]) * sign, + h: toInt(match[HOUR]) * sign, + m: toInt(match[MINUTE]) * sign, + s: toInt(match[SECOND]) * sign, + ms: toInt(match[MILLISECOND]) * sign + }; + } else if (!!(match = isoDurationRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + parseIso = function (inp) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; + }; + duration = { + y: parseIso(match[2]), + M: parseIso(match[3]), + d: parseIso(match[4]), + h: parseIso(match[5]), + m: parseIso(match[6]), + s: parseIso(match[7]), + w: parseIso(match[8]) + }; + } else if (typeof duration === 'object' && + ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(moment(duration.from), moment(duration.to)); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } + + ret = new Duration(duration); + + if (moment.isDuration(input) && input.hasOwnProperty('_locale')) { + ret._locale = input._locale; + } + + return ret; + }; + + // version number + moment.version = VERSION; + + // default format + moment.defaultFormat = isoFormat; + + // constant that refers to the ISO standard + moment.ISO_8601 = function () {}; + + // Plugins that add properties should also add the key here (null value), + // so we can properly clone ourselves. + moment.momentProperties = momentProperties; + + // This function will be called whenever a moment is mutated. + // It is intended to keep the offset in sync with the timezone. + moment.updateOffset = function () {}; + + // This function allows you to set a threshold for relative time strings + moment.relativeTimeThreshold = function (threshold, limit) { + if (relativeTimeThresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return relativeTimeThresholds[threshold]; + } + relativeTimeThresholds[threshold] = limit; + return true; + }; + + moment.lang = deprecate( + "moment.lang is deprecated. Use moment.locale instead.", + function (key, value) { + return moment.locale(key, value); + } + ); + + // This function will load locale and then set the global locale. If + // no arguments are passed in, it will simply return the current global + // locale key. + moment.locale = function (key, values) { + var data; + if (key) { + if (typeof(values) !== "undefined") { + data = moment.defineLocale(key, values); + } + else { + data = moment.localeData(key); + } + + if (data) { + moment.duration._locale = moment._locale = data; + } + } + + return moment._locale._abbr; + }; + + moment.defineLocale = function (name, values) { + if (values !== null) { + values.abbr = name; + if (!locales[name]) { + locales[name] = new Locale(); + } + locales[name].set(values); + + // backwards compat for now: also set the locale + moment.locale(name); + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } + }; + + moment.langData = deprecate( + "moment.langData is deprecated. Use moment.localeData instead.", + function (key) { + return moment.localeData(key); + } + ); + + // returns locale data + moment.localeData = function (key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return moment._locale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); + }; + + // compare moment object + moment.isMoment = function (obj) { + return obj instanceof Moment || + (obj != null && obj.hasOwnProperty('_isAMomentObject')); + }; + + // for typechecking Duration objects + moment.isDuration = function (obj) { + return obj instanceof Duration; + }; + + for (i = lists.length - 1; i >= 0; --i) { + makeList(lists[i]); + } + + moment.normalizeUnits = function (units) { + return normalizeUnits(units); + }; + + moment.invalid = function (flags) { + var m = moment.utc(NaN); + if (flags != null) { + extend(m._pf, flags); + } + else { + m._pf.userInvalidated = true; + } + + return m; + }; + + moment.parseZone = function () { + return moment.apply(null, arguments).parseZone(); + }; + + moment.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); + }; + + /************************************ + Moment Prototype + ************************************/ + + + extend(moment.fn = Moment.prototype, { + + clone : function () { + return moment(this); + }, + + valueOf : function () { + return +this._d + ((this._offset || 0) * 60000); + }, + + unix : function () { + return Math.floor(+this / 1000); + }, + + toString : function () { + return this.clone().locale('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); + }, + + toDate : function () { + return this._offset ? new Date(+this) : this._d; + }, + + toISOString : function () { + var m = moment(this).utc(); + if (0 < m.year() && m.year() <= 9999) { + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } else { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + }, + + toArray : function () { + var m = this; + return [ + m.year(), + m.month(), + m.date(), + m.hours(), + m.minutes(), + m.seconds(), + m.milliseconds() + ]; + }, + + isValid : function () { + return isValid(this); + }, + + isDSTShifted : function () { + if (this._a) { + return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; + } + + return false; + }, + + parsingFlags : function () { + return extend({}, this._pf); + }, + + invalidAt: function () { + return this._pf.overflow; + }, + + utc : function (keepLocalTime) { + return this.zone(0, keepLocalTime); + }, + + local : function (keepLocalTime) { + if (this._isUTC) { + this.zone(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.add(this._d.getTimezoneOffset(), 'm'); + } + } + return this; + }, + + format : function (inputString) { + var output = formatMoment(this, inputString || moment.defaultFormat); + return this.localeData().postformat(output); + }, + + add : createAdder(1, 'add'), + + subtract : createAdder(-1, 'subtract'), + + diff : function (input, units, asFloat) { + var that = makeAs(input, this), + zoneDiff = (this.zone() - that.zone()) * 6e4, + diff, output; + + units = normalizeUnits(units); + + if (units === 'year' || units === 'month') { + // average number of days in the months in the given dates + diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 + // difference in months + output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); + // adjust by taking difference in days, average number of days + // and dst in the given months. + output += ((this - moment(this).startOf('month')) - + (that - moment(that).startOf('month'))) / diff; + // same as above but with zones, to negate all dst + output -= ((this.zone() - moment(this).startOf('month').zone()) - + (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff; + if (units === 'year') { + output = output / 12; + } + } else { + diff = (this - that); + output = units === 'second' ? diff / 1e3 : // 1000 + units === 'minute' ? diff / 6e4 : // 1000 * 60 + units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + diff; + } + return asFloat ? output : absRound(output); + }, + + from : function (time, withoutSuffix) { + return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + }, + + fromNow : function (withoutSuffix) { + return this.from(moment(), withoutSuffix); + }, + + calendar : function (time) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're zone'd or not. + var now = time || moment(), + sod = makeAs(now, this).startOf('day'), + diff = this.diff(sod, 'days', true), + format = diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; + return this.format(this.localeData().calendar(format, this)); + }, + + isLeapYear : function () { + return isLeapYear(this.year()); + }, + + isDST : function () { + return (this.zone() < this.clone().month(0).zone() || + this.zone() < this.clone().month(5).zone()); + }, + + day : function (input) { + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } + }, + + month : makeAccessor('Month', true), + + startOf : function (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + /* falls through */ + } + + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } else if (units === 'isoWeek') { + this.isoWeekday(1); + } + + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } + + return this; + }, + + endOf: function (units) { + units = normalizeUnits(units); + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); + }, + + isAfter: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) > +moment(input).startOf(units); + }, + + isBefore: function (input, units) { + units = typeof units !== 'undefined' ? units : 'millisecond'; + return +this.clone().startOf(units) < +moment(input).startOf(units); + }, + + isSame: function (input, units) { + units = units || 'ms'; + return +this.clone().startOf(units) === +makeAs(input, this).startOf(units); + }, + + min: deprecate( + 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', + function (other) { + other = moment.apply(null, arguments); + return other < this ? this : other; + } + ), + + max: deprecate( + 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', + function (other) { + other = moment.apply(null, arguments); + return other > this ? this : other; + } + ), + + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[zone(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist int zone + // +0200, so we adjust the time as needed, to be valid. + // + // Keeping the time actually adds/subtracts (one hour) + // from the actual represented time. That is why we call updateOffset + // a second time. In case it wants us to change the offset again + // _changeInProgress == true case, then we have to adjust, because + // there is no such time in the given timezone. + zone : function (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; + if (input != null) { + if (typeof input === 'string') { + input = timezoneMinutesFromString(input); + } + if (Math.abs(input) < 16) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = this._d.getTimezoneOffset(); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.subtract(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addOrSubtractDurationFromMoment(this, + moment.duration(offset - input, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + moment.updateOffset(this, true); + this._changeInProgress = null; + } + } + } else { + return this._isUTC ? offset : this._d.getTimezoneOffset(); + } + return this; + }, + + zoneAbbr : function () { + return this._isUTC ? 'UTC' : ''; + }, + + zoneName : function () { + return this._isUTC ? 'Coordinated Universal Time' : ''; + }, + + parseZone : function () { + if (this._tzm) { + this.zone(this._tzm); + } else if (typeof this._i === 'string') { + this.zone(this._i); + } + return this; + }, + + hasAlignedHourOffset : function (input) { + if (!input) { + input = 0; + } + else { + input = moment(input).zone(); + } + + return (this.zone() - input) % 60 === 0; + }, + + daysInMonth : function () { + return daysInMonth(this.year(), this.month()); + }, + + dayOfYear : function (input) { + var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); + }, + + quarter : function (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); + }, + + weekYear : function (input) { + var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; + return input == null ? year : this.add((input - year), 'y'); + }, + + isoWeekYear : function (input) { + var year = weekOfYear(this, 1, 4).year; + return input == null ? year : this.add((input - year), 'y'); + }, + + week : function (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); + }, + + isoWeek : function (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); + }, + + weekday : function (input) { + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); + }, + + isoWeekday : function (input) { + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); + }, + + isoWeeksInYear : function () { + return weeksInYear(this.year(), 1, 4); + }, + + weeksInYear : function () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units](); + }, + + set : function (units, value) { + units = normalizeUnits(units); + if (typeof this[units] === 'function') { + this[units](value); + } + return this; + }, + + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration + // variables for this instance. + locale : function (key) { + if (key === undefined) { + return this._locale._abbr; + } else { + this._locale = moment.localeData(key); + return this; + } + }, + + lang : deprecate( + "moment().lang() is deprecated. Use moment().localeData() instead.", + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + this._locale = moment.localeData(key); + return this; + } + } + ), + + localeData : function () { + return this._locale; + } + }); + + function rawMonthSetter(mom, value) { + var dayOfMonth; + + // TODO: Move this out of here! + if (typeof value === 'string') { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (typeof value !== 'number') { + return mom; + } + } + + dayOfMonth = Math.min(mom.date(), + daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; + } + + function rawGetter(mom, unit) { + return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); + } + + function rawSetter(mom, unit, value) { + if (unit === 'Month') { + return rawMonthSetter(mom, value); + } else { + return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } + } + + function makeAccessor(unit, keepTime) { + return function (value) { + if (value != null) { + rawSetter(this, unit, value); + moment.updateOffset(this, keepTime); + return this; + } else { + return rawGetter(this, unit); + } + }; + } + + moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); + moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); + moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); + // Setting the hour should keep the time, because the user explicitly + // specified which hour he wants. So trying to maintain the same hour (in + // a new timezone) makes sense. Adding/subtracting hours does not follow + // this rule. + moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true); + // moment.fn.month is defined separately + moment.fn.date = makeAccessor('Date', true); + moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true)); + moment.fn.year = makeAccessor('FullYear', true); + moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); + + // add plural methods + moment.fn.days = moment.fn.day; + moment.fn.months = moment.fn.month; + moment.fn.weeks = moment.fn.week; + moment.fn.isoWeeks = moment.fn.isoWeek; + moment.fn.quarters = moment.fn.quarter; + + // add aliased format methods + moment.fn.toJSON = moment.fn.toISOString; + + /************************************ + Duration Prototype + ************************************/ + + + function daysToYears (days) { + // 400 years have 146097 days (taking into account leap year rules) + return days * 400 / 146097; + } + + function yearsToDays (years) { + // years * 365 + absRound(years / 4) - + // absRound(years / 100) + absRound(years / 400); + return years * 146097 / 400; + } + + extend(moment.duration.fn = Duration.prototype, { + + _bubble : function () { + var milliseconds = this._milliseconds, + days = this._days, + months = this._months, + data = this._data, + seconds, minutes, hours, years = 0; + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absRound(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absRound(seconds / 60); + data.minutes = minutes % 60; + + hours = absRound(minutes / 60); + data.hours = hours % 24; + + days += absRound(hours / 24); + + // Accurately convert days to years, assume start from year 0. + years = absRound(daysToYears(days)); + days -= absRound(yearsToDays(years)); + + // 30 days to a month + // TODO (iskren): Use anchor date (like 1st Jan) to compute this. + months += absRound(days / 30); + days %= 30; + + // 12 months -> 1 year + years += absRound(months / 12); + months %= 12; + + data.days = days; + data.months = months; + data.years = years; + }, + + abs : function () { + this._milliseconds = Math.abs(this._milliseconds); + this._days = Math.abs(this._days); + this._months = Math.abs(this._months); + + this._data.milliseconds = Math.abs(this._data.milliseconds); + this._data.seconds = Math.abs(this._data.seconds); + this._data.minutes = Math.abs(this._data.minutes); + this._data.hours = Math.abs(this._data.hours); + this._data.months = Math.abs(this._data.months); + this._data.years = Math.abs(this._data.years); + + return this; + }, + + weeks : function () { + return absRound(this.days() / 7); + }, + + valueOf : function () { + return this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6; + }, + + humanize : function (withSuffix) { + var output = relativeTime(this, !withSuffix, this.localeData()); + + if (withSuffix) { + output = this.localeData().pastFuture(+this, output); + } + + return this.localeData().postformat(output); + }, + + add : function (input, val) { + // supports only 2.0-style add(1, 's') or add(moment) + var dur = moment.duration(input, val); + + this._milliseconds += dur._milliseconds; + this._days += dur._days; + this._months += dur._months; + + this._bubble(); + + return this; + }, + + subtract : function (input, val) { + var dur = moment.duration(input, val); + + this._milliseconds -= dur._milliseconds; + this._days -= dur._days; + this._months -= dur._months; + + this._bubble(); + + return this; + }, + + get : function (units) { + units = normalizeUnits(units); + return this[units.toLowerCase() + 's'](); + }, + + as : function (units) { + var days, months; + units = normalizeUnits(units); + + days = this._days + this._milliseconds / 864e5; + if (units === 'month' || units === 'year') { + months = this._months + daysToYears(days) * 12; + return units === 'month' ? months : months / 12; + } else { + days += yearsToDays(this._months / 12); + switch (units) { + case 'week': return days / 7; + case 'day': return days; + case 'hour': return days * 24; + case 'minute': return days * 24 * 60; + case 'second': return days * 24 * 60 * 60; + case 'millisecond': return days * 24 * 60 * 60 * 1000; + default: throw new Error('Unknown unit ' + units); + } + } + }, + + lang : moment.fn.lang, + locale : moment.fn.locale, + + toIsoString : deprecate( + "toIsoString() is deprecated. Please use toISOString() instead " + + "(notice the capitals)", + function () { + return this.toISOString(); + } + ), + + toISOString : function () { + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var years = Math.abs(this.years()), + months = Math.abs(this.months()), + days = Math.abs(this.days()), + hours = Math.abs(this.hours()), + minutes = Math.abs(this.minutes()), + seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); + + if (!this.asSeconds()) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + return (this.asSeconds() < 0 ? '-' : '') + + 'P' + + (years ? years + 'Y' : '') + + (months ? months + 'M' : '') + + (days ? days + 'D' : '') + + ((hours || minutes || seconds) ? 'T' : '') + + (hours ? hours + 'H' : '') + + (minutes ? minutes + 'M' : '') + + (seconds ? seconds + 'S' : ''); + }, + + localeData : function () { + return this._locale; + } + }); + + function makeDurationGetter(name) { + moment.duration.fn[name] = function () { + return this._data[name]; + }; + } + + for (i in unitMillisecondFactors) { + if (unitMillisecondFactors.hasOwnProperty(i)) { + makeDurationGetter(i.toLowerCase()); + } + } + + moment.duration.fn.asMilliseconds = function () { + return this.as('ms'); + }; + moment.duration.fn.asSeconds = function () { + return this.as('s'); + }; + moment.duration.fn.asMinutes = function () { + return this.as('m'); + }; + moment.duration.fn.asHours = function () { + return this.as('h'); + }; + moment.duration.fn.asDays = function () { + return this.as('d'); + }; + moment.duration.fn.asWeeks = function () { + return this.as('weeks'); + }; + moment.duration.fn.asMonths = function () { + return this.as('M'); + }; + moment.duration.fn.asYears = function () { + return this.as('y'); + }; + + /************************************ + Default Locale + ************************************/ + + + // Set default locale, other locale will inherit from English. + moment.locale('en', { + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } + }); + + /* EMBED_LOCALES */ + + /************************************ + Exposing Moment + ************************************/ + + function makeGlobal(shouldDeprecate) { + /*global ender:false */ + if (typeof ender !== 'undefined') { + return; + } + oldGlobalMoment = globalScope.moment; + if (shouldDeprecate) { + globalScope.moment = deprecate( + 'Accessing Moment through the global scope is ' + + 'deprecated, and will be removed in an upcoming ' + + 'release.', + moment); + } else { + globalScope.moment = moment; + } + } + + // CommonJS module is defined + if (hasModule) { + module.exports = moment; + } else if (typeof define === 'function' && define.amd) { + define('moment', function (require, exports, module) { + if (module.config && module.config() && module.config().noGlobal === true) { + // release the global variable + globalScope.moment = oldGlobalMoment; + } + + return moment; + }); + makeGlobal(true); + } else { + makeGlobal(); + } }).call(this); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/moment.min.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/moment.min.js index c30bbff2..197b5488 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/moment.min.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-daterangepicker/moment.min.js @@ -1,6 +1,6 @@ -//! moment.js -//! version : 2.8.1 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors -//! license : MIT -//! momentjs.com +//! moment.js +//! version : 2.8.1 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com (function(a){function b(a,b,c){switch(arguments.length){case 2:return null!=a?a:b;case 3:return null!=a?a:null!=b?b:c;default:throw new Error("Implement me")}}function c(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function d(a){rb.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+a)}function e(a,b){var c=!0;return l(function(){return c&&(d(a),c=!1),b.apply(this,arguments)},b)}function f(a,b){nc[a]||(d(b),nc[a]=!0)}function g(a,b){return function(c){return o(a.call(this,c),b)}}function h(a,b){return function(c){return this.localeData().ordinal(a.call(this,c),b)}}function i(){}function j(a,b){b!==!1&&E(a),m(this,a),this._d=new Date(+a._d)}function k(a){var b=x(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;this._milliseconds=+k+1e3*j+6e4*i+36e5*h,this._days=+g+7*f,this._months=+e+3*d+12*c,this._data={},this._locale=rb.localeData(),this._bubble()}function l(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return b.hasOwnProperty("toString")&&(a.toString=b.toString),b.hasOwnProperty("valueOf")&&(a.valueOf=b.valueOf),a}function m(a,b){var c,d,e;if("undefined"!=typeof b._isAMomentObject&&(a._isAMomentObject=b._isAMomentObject),"undefined"!=typeof b._i&&(a._i=b._i),"undefined"!=typeof b._f&&(a._f=b._f),"undefined"!=typeof b._l&&(a._l=b._l),"undefined"!=typeof b._strict&&(a._strict=b._strict),"undefined"!=typeof b._tzm&&(a._tzm=b._tzm),"undefined"!=typeof b._isUTC&&(a._isUTC=b._isUTC),"undefined"!=typeof b._offset&&(a._offset=b._offset),"undefined"!=typeof b._pf&&(a._pf=b._pf),"undefined"!=typeof b._locale&&(a._locale=b._locale),Fb.length>0)for(c in Fb)d=Fb[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function n(a){return 0>a?Math.ceil(a):Math.floor(a)}function o(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthd;d++)(c&&a[d]!==b[d]||!c&&z(a[d])!==z(b[d]))&&g++;return g+f}function w(a){if(a){var b=a.toLowerCase().replace(/(.)s$/,"$1");a=gc[a]||hc[b]||b}return a}function x(a){var b,c,d={};for(c in a)a.hasOwnProperty(c)&&(b=w(c),b&&(d[b]=a[c]));return d}function y(b){var c,d;if(0===b.indexOf("week"))c=7,d="day";else{if(0!==b.indexOf("month"))return;c=12,d="month"}rb[b]=function(e,f){var g,h,i=rb._locale[b],j=[];if("number"==typeof e&&(f=e,e=a),h=function(a){var b=rb().utc().set(d,a);return i.call(rb._locale,b,e||"")},null!=f)return h(f);for(g=0;c>g;g++)j.push(h(g));return j}}function z(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function A(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function B(a,b,c){return fb(rb([a,11,31+b-c]),b,c).week}function C(a){return D(a)?366:365}function D(a){return a%4===0&&a%100!==0||a%400===0}function E(a){var b;a._a&&-2===a._pf.overflow&&(b=a._a[yb]<0||a._a[yb]>11?yb:a._a[zb]<1||a._a[zb]>A(a._a[xb],a._a[yb])?zb:a._a[Ab]<0||a._a[Ab]>23?Ab:a._a[Bb]<0||a._a[Bb]>59?Bb:a._a[Cb]<0||a._a[Cb]>59?Cb:a._a[Db]<0||a._a[Db]>999?Db:-1,a._pf._overflowDayOfYear&&(xb>b||b>zb)&&(b=zb),a._pf.overflow=b)}function F(a){return null==a._isValid&&(a._isValid=!isNaN(a._d.getTime())&&a._pf.overflow<0&&!a._pf.empty&&!a._pf.invalidMonth&&!a._pf.nullInput&&!a._pf.invalidFormat&&!a._pf.userInvalidated,a._strict&&(a._isValid=a._isValid&&0===a._pf.charsLeftOver&&0===a._pf.unusedTokens.length)),a._isValid}function G(a){return a?a.toLowerCase().replace("_","-"):a}function H(a){for(var b,c,d,e,f=0;f0;){if(d=I(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&v(e,c,!0)>=b-1)break;b--}f++}return null}function I(a){var b=null;if(!Eb[a]&&Gb)try{b=rb.locale(),require("./locale/"+a),rb.locale(b)}catch(c){}return Eb[a]}function J(a,b){return b._isUTC?rb(a).zone(b._offset||0):rb(a).local()}function K(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function L(a){var b,c,d=a.match(Kb);for(b=0,c=d.length;c>b;b++)d[b]=mc[d[b]]?mc[d[b]]:K(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function M(a,b){return a.isValid()?(b=N(b,a.localeData()),ic[b]||(ic[b]=L(b)),ic[b](a)):a.localeData().invalidDate()}function N(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Lb.lastIndex=0;d>=0&&Lb.test(a);)a=a.replace(Lb,c),Lb.lastIndex=0,d-=1;return a}function O(a,b){var c,d=b._strict;switch(a){case"Q":return Wb;case"DDDD":return Yb;case"YYYY":case"GGGG":case"gggg":return d?Zb:Ob;case"Y":case"G":case"g":return _b;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return d?$b:Pb;case"S":if(d)return Wb;case"SS":if(d)return Xb;case"SSS":if(d)return Yb;case"DDD":return Nb;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Rb;case"a":case"A":return b._locale._meridiemParse;case"X":return Ub;case"Z":case"ZZ":return Sb;case"T":return Tb;case"SSSS":return Qb;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return d?Xb:Mb;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Mb;case"Do":return Vb;default:return c=new RegExp(X(W(a.replace("\\","")),"i"))}}function P(a){a=a||"";var b=a.match(Sb)||[],c=b[b.length-1]||[],d=(c+"").match(ec)||["-",0,0],e=+(60*d[1])+z(d[2]);return"+"===d[0]?-e:e}function Q(a,b,c){var d,e=c._a;switch(a){case"Q":null!=b&&(e[yb]=3*(z(b)-1));break;case"M":case"MM":null!=b&&(e[yb]=z(b)-1);break;case"MMM":case"MMMM":d=c._locale.monthsParse(b),null!=d?e[yb]=d:c._pf.invalidMonth=b;break;case"D":case"DD":null!=b&&(e[zb]=z(b));break;case"Do":null!=b&&(e[zb]=z(parseInt(b,10)));break;case"DDD":case"DDDD":null!=b&&(c._dayOfYear=z(b));break;case"YY":e[xb]=rb.parseTwoDigitYear(b);break;case"YYYY":case"YYYYY":case"YYYYYY":e[xb]=z(b);break;case"a":case"A":c._isPm=c._locale.isPM(b);break;case"H":case"HH":case"h":case"hh":e[Ab]=z(b);break;case"m":case"mm":e[Bb]=z(b);break;case"s":case"ss":e[Cb]=z(b);break;case"S":case"SS":case"SSS":case"SSSS":e[Db]=z(1e3*("0."+b));break;case"X":c._d=new Date(1e3*parseFloat(b));break;case"Z":case"ZZ":c._useUTC=!0,c._tzm=P(b);break;case"dd":case"ddd":case"dddd":d=c._locale.weekdaysParse(b),null!=d?(c._w=c._w||{},c._w.d=d):c._pf.invalidWeekday=b;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":a=a.substr(0,1);case"gggg":case"GGGG":case"GGGGG":a=a.substr(0,2),b&&(c._w=c._w||{},c._w[a]=z(b));break;case"gg":case"GG":c._w=c._w||{},c._w[a]=rb.parseTwoDigitYear(b)}}function R(a){var c,d,e,f,g,h,i;c=a._w,null!=c.GG||null!=c.W||null!=c.E?(g=1,h=4,d=b(c.GG,a._a[xb],fb(rb(),1,4).year),e=b(c.W,1),f=b(c.E,1)):(g=a._locale._week.dow,h=a._locale._week.doy,d=b(c.gg,a._a[xb],fb(rb(),g,h).year),e=b(c.w,1),null!=c.d?(f=c.d,g>f&&++e):f=null!=c.e?c.e+g:g),i=gb(d,e,f,h,g),a._a[xb]=i.year,a._dayOfYear=i.dayOfYear}function S(a){var c,d,e,f,g=[];if(!a._d){for(e=U(a),a._w&&null==a._a[zb]&&null==a._a[yb]&&R(a),a._dayOfYear&&(f=b(a._a[xb],e[xb]),a._dayOfYear>C(f)&&(a._pf._overflowDayOfYear=!0),d=bb(f,0,a._dayOfYear),a._a[yb]=d.getUTCMonth(),a._a[zb]=d.getUTCDate()),c=0;3>c&&null==a._a[c];++c)a._a[c]=g[c]=e[c];for(;7>c;c++)a._a[c]=g[c]=null==a._a[c]?2===c?1:0:a._a[c];a._d=(a._useUTC?bb:ab).apply(null,g),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()+a._tzm)}}function T(a){var b;a._d||(b=x(a._i),a._a=[b.year,b.month,b.day,b.hour,b.minute,b.second,b.millisecond],S(a))}function U(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function V(a){if(a._f===rb.ISO_8601)return void Z(a);a._a=[],a._pf.empty=!0;var b,c,d,e,f,g=""+a._i,h=g.length,i=0;for(d=N(a._f,a._locale).match(Kb)||[],b=0;b0&&a._pf.unusedInput.push(f),g=g.slice(g.indexOf(c)+c.length),i+=c.length),mc[e]?(c?a._pf.empty=!1:a._pf.unusedTokens.push(e),Q(e,c,a)):a._strict&&!c&&a._pf.unusedTokens.push(e);a._pf.charsLeftOver=h-i,g.length>0&&a._pf.unusedInput.push(g),a._isPm&&a._a[Ab]<12&&(a._a[Ab]+=12),a._isPm===!1&&12===a._a[Ab]&&(a._a[Ab]=0),S(a),E(a)}function W(a){return a.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e})}function X(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function Y(a){var b,d,e,f,g;if(0===a._f.length)return a._pf.invalidFormat=!0,void(a._d=new Date(0/0));for(f=0;fg)&&(e=g,d=b));l(a,d||b)}function Z(a){var b,c,d=a._i,e=ac.exec(d);if(e){for(a._pf.iso=!0,b=0,c=cc.length;c>b;b++)if(cc[b][1].exec(d)){a._f=cc[b][0]+(e[6]||" ");break}for(b=0,c=dc.length;c>b;b++)if(dc[b][1].exec(d)){a._f+=dc[b][0];break}d.match(Sb)&&(a._f+="Z"),V(a)}else a._isValid=!1}function $(a){Z(a),a._isValid===!1&&(delete a._isValid,rb.createFromInputFallback(a))}function _(b){var c,d=b._i;d===a?b._d=new Date:u(d)?b._d=new Date(+d):null!==(c=Hb.exec(d))?b._d=new Date(+c[1]):"string"==typeof d?$(b):t(d)?(b._a=d.slice(0),S(b)):"object"==typeof d?T(b):"number"==typeof d?b._d=new Date(d):rb.createFromInputFallback(b)}function ab(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function bb(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function cb(a,b){if("string"==typeof a)if(isNaN(a)){if(a=b.weekdaysParse(a),"number"!=typeof a)return null}else a=parseInt(a,10);return a}function db(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function eb(a,b,c){var d=rb.duration(a).abs(),e=wb(d.as("s")),f=wb(d.as("m")),g=wb(d.as("h")),h=wb(d.as("d")),i=wb(d.as("M")),j=wb(d.as("y")),k=e0,k[4]=c,db.apply({},k)}function fb(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=rb(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function gb(a,b,c,d,e){var f,g,h=bb(a,0,1).getUTCDay();return h=0===h?7:h,c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:C(a-1)+g}}function hb(b){var c=b._i,d=b._f;return b._locale=b._locale||rb.localeData(b._l),null===c||d===a&&""===c?rb.invalid({nullInput:!0}):("string"==typeof c&&(b._i=c=b._locale.preparse(c)),rb.isMoment(c)?new j(c,!0):(d?t(d)?Y(b):V(b):_(b),new j(b)))}function ib(a,b){var c,d;if(1===b.length&&t(b[0])&&(b=b[0]),!b.length)return rb();for(c=b[0],d=1;d=0?"+":"-";return b+o(Math.abs(a),6)},gg:function(){return o(this.weekYear()%100,2)},gggg:function(){return o(this.weekYear(),4)},ggggg:function(){return o(this.weekYear(),5)},GG:function(){return o(this.isoWeekYear()%100,2)},GGGG:function(){return o(this.isoWeekYear(),4)},GGGGG:function(){return o(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return z(this.milliseconds()/100)},SS:function(){return o(z(this.milliseconds()/10),2)},SSS:function(){return o(this.milliseconds(),3)},SSSS:function(){return o(this.milliseconds(),3)},Z:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+o(z(a/60),2)+":"+o(z(a)%60,2)},ZZ:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+o(z(a/60),2)+o(z(a)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},nc={},oc=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];kc.length;)tb=kc.pop(),mc[tb+"o"]=h(mc[tb],tb);for(;lc.length;)tb=lc.pop(),mc[tb+tb]=g(mc[tb],2);mc.DDDD=g(mc.DDD,3),l(i.prototype,{set:function(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(a){return this._months[a.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(a){return this._monthsShort[a.month()]},monthsParse:function(a){var b,c,d;for(this._monthsParse||(this._monthsParse=[]),b=0;12>b;b++)if(this._monthsParse[b]||(c=rb.utc([2e3,b]),d="^"+this.months(c,"")+"|^"+this.monthsShort(c,""),this._monthsParse[b]=new RegExp(d.replace(".",""),"i")),this._monthsParse[b].test(a))return b},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(a){return this._weekdays[a.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(a){return this._weekdaysShort[a.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(a){return this._weekdaysMin[a.day()]},weekdaysParse:function(a){var b,c,d;for(this._weekdaysParse||(this._weekdaysParse=[]),b=0;7>b;b++)if(this._weekdaysParse[b]||(c=rb([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"},longDateFormat:function(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b},isPM:function(a){return"p"===(a+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(a,b){var c=this._calendar[a];return"function"==typeof c?c.apply(b):c},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)},pastFuture:function(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)},ordinal:function(a){return this._ordinal.replace("%d",a)},_ordinal:"%d",preparse:function(a){return a},postformat:function(a){return a},week:function(a){return fb(a,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),rb=function(b,d,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._i=b,g._f=d,g._l=e,g._strict=f,g._isUTC=!1,g._pf=c(),hb(g)},rb.suppressDeprecationWarnings=!1,rb.createFromInputFallback=e("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i)}),rb.min=function(){var a=[].slice.call(arguments,0);return ib("isBefore",a)},rb.max=function(){var a=[].slice.call(arguments,0);return ib("isAfter",a)},rb.utc=function(b,d,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._useUTC=!0,g._isUTC=!0,g._l=e,g._i=b,g._f=d,g._strict=f,g._pf=c(),hb(g).utc()},rb.unix=function(a){return rb(1e3*a)},rb.duration=function(a,b){var c,d,e,f,g=a,h=null;return rb.isDuration(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=Ib.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:z(h[zb])*c,h:z(h[Ab])*c,m:z(h[Bb])*c,s:z(h[Cb])*c,ms:z(h[Db])*c}):(h=Jb.exec(a))?(c="-"===h[1]?-1:1,e=function(a){var b=a&&parseFloat(a.replace(",","."));return(isNaN(b)?0:b)*c},g={y:e(h[2]),M:e(h[3]),d:e(h[4]),h:e(h[5]),m:e(h[6]),s:e(h[7]),w:e(h[8])}):"object"==typeof g&&("from"in g||"to"in g)&&(f=q(rb(g.from),rb(g.to)),g={},g.ms=f.milliseconds,g.M=f.months),d=new k(g),rb.isDuration(a)&&a.hasOwnProperty("_locale")&&(d._locale=a._locale),d},rb.version=ub,rb.defaultFormat=bc,rb.ISO_8601=function(){},rb.momentProperties=Fb,rb.updateOffset=function(){},rb.relativeTimeThreshold=function(b,c){return jc[b]===a?!1:c===a?jc[b]:(jc[b]=c,!0)},rb.lang=e("moment.lang is deprecated. Use moment.locale instead.",function(a,b){return rb.locale(a,b)}),rb.locale=function(a,b){var c;return a&&(c="undefined"!=typeof b?rb.defineLocale(a,b):rb.localeData(a),c&&(rb.duration._locale=rb._locale=c)),rb._locale._abbr},rb.defineLocale=function(a,b){return null!==b?(b.abbr=a,Eb[a]||(Eb[a]=new i),Eb[a].set(b),rb.locale(a),Eb[a]):(delete Eb[a],null)},rb.langData=e("moment.langData is deprecated. Use moment.localeData instead.",function(a){return rb.localeData(a)}),rb.localeData=function(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return rb._locale;if(!t(a)){if(b=I(a))return b;a=[a]}return H(a)},rb.isMoment=function(a){return a instanceof j||null!=a&&a.hasOwnProperty("_isAMomentObject")},rb.isDuration=function(a){return a instanceof k};for(tb=oc.length-1;tb>=0;--tb)y(oc[tb]);rb.normalizeUnits=function(a){return w(a)},rb.invalid=function(a){var b=rb.utc(0/0);return null!=a?l(b._pf,a):b._pf.userInvalidated=!0,b},rb.parseZone=function(){return rb.apply(null,arguments).parseZone()},rb.parseTwoDigitYear=function(a){return z(a)+(z(a)>68?1900:2e3)},l(rb.fn=j.prototype,{clone:function(){return rb(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var a=rb(this).utc();return 00:!1},parsingFlags:function(){return l({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(a){return this.zone(0,a)},local:function(a){return this._isUTC&&(this.zone(0,a),this._isUTC=!1,a&&this.add(this._d.getTimezoneOffset(),"m")),this},format:function(a){var b=M(this,a||rb.defaultFormat);return this.localeData().postformat(b)},add:r(1,"add"),subtract:r(-1,"subtract"),diff:function(a,b,c){var d,e,f=J(a,this),g=6e4*(this.zone()-f.zone());return b=w(b),"year"===b||"month"===b?(d=432e5*(this.daysInMonth()+f.daysInMonth()),e=12*(this.year()-f.year())+(this.month()-f.month()),e+=(this-rb(this).startOf("month")-(f-rb(f).startOf("month")))/d,e-=6e4*(this.zone()-rb(this).startOf("month").zone()-(f.zone()-rb(f).startOf("month").zone()))/d,"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:n(e)},from:function(a,b){return rb.duration({to:this,from:a}).locale(this.locale()).humanize(!b)},fromNow:function(a){return this.from(rb(),a)},calendar:function(a){var b=a||rb(),c=J(b,this).startOf("day"),d=this.diff(c,"days",!0),e=-6>d?"sameElse":-1>d?"lastWeek":0>d?"lastDay":1>d?"sameDay":2>d?"nextDay":7>d?"nextWeek":"sameElse";return this.format(this.localeData().calendar(e,this))},isLeapYear:function(){return D(this.year())},isDST:function(){return this.zone()+rb(a).startOf(b)},isBefore:function(a,b){return b="undefined"!=typeof b?b:"millisecond",+this.clone().startOf(b)<+rb(a).startOf(b)},isSame:function(a,b){return b=b||"ms",+this.clone().startOf(b)===+J(a,this).startOf(b)},min:e("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(a){return a=rb.apply(null,arguments),this>a?this:a}),max:e("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(a){return a=rb.apply(null,arguments),a>this?this:a}),zone:function(a,b){var c,d=this._offset||0;return null==a?this._isUTC?d:this._d.getTimezoneOffset():("string"==typeof a&&(a=P(a)),Math.abs(a)<16&&(a=60*a),!this._isUTC&&b&&(c=this._d.getTimezoneOffset()),this._offset=a,this._isUTC=!0,null!=c&&this.subtract(c,"m"),d!==a&&(!b||this._changeInProgress?s(this,rb.duration(d-a,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,rb.updateOffset(this,!0),this._changeInProgress=null)),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(a){return a=a?rb(a).zone():0,(this.zone()-a)%60===0},daysInMonth:function(){return A(this.year(),this.month())},dayOfYear:function(a){var b=wb((rb(this).startOf("day")-rb(this).startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")},quarter:function(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)},weekYear:function(a){var b=fb(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==a?b:this.add(a-b,"y")},isoWeekYear:function(a){var b=fb(this,1,4).year;return null==a?b:this.add(a-b,"y")},week:function(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")},isoWeek:function(a){var b=fb(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")},weekday:function(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")},isoWeekday:function(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)},isoWeeksInYear:function(){return B(this.year(),1,4)},weeksInYear:function(){var a=this.localeData()._week;return B(this.year(),a.dow,a.doy)},get:function(a){return a=w(a),this[a]()},set:function(a,b){return a=w(a),"function"==typeof this[a]&&this[a](b),this},locale:function(b){return b===a?this._locale._abbr:(this._locale=rb.localeData(b),this)},lang:e("moment().lang() is deprecated. Use moment().localeData() instead.",function(b){return b===a?this.localeData():(this._locale=rb.localeData(b),this)}),localeData:function(){return this._locale}}),rb.fn.millisecond=rb.fn.milliseconds=mb("Milliseconds",!1),rb.fn.second=rb.fn.seconds=mb("Seconds",!1),rb.fn.minute=rb.fn.minutes=mb("Minutes",!1),rb.fn.hour=rb.fn.hours=mb("Hours",!0),rb.fn.date=mb("Date",!0),rb.fn.dates=e("dates accessor is deprecated. Use date instead.",mb("Date",!0)),rb.fn.year=mb("FullYear",!0),rb.fn.years=e("years accessor is deprecated. Use year instead.",mb("FullYear",!0)),rb.fn.days=rb.fn.day,rb.fn.months=rb.fn.month,rb.fn.weeks=rb.fn.week,rb.fn.isoWeeks=rb.fn.isoWeek,rb.fn.quarters=rb.fn.quarter,rb.fn.toJSON=rb.fn.toISOString,l(rb.duration.fn=k.prototype,{_bubble:function(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;g.milliseconds=d%1e3,a=n(d/1e3),g.seconds=a%60,b=n(a/60),g.minutes=b%60,c=n(b/60),g.hours=c%24,e+=n(c/24),h=n(nb(e)),e-=n(ob(h)),f+=n(e/30),e%=30,h+=n(f/12),f%=12,g.days=e,g.months=f,g.years=h},abs:function(){return this._milliseconds=Math.abs(this._milliseconds),this._days=Math.abs(this._days),this._months=Math.abs(this._months),this._data.milliseconds=Math.abs(this._data.milliseconds),this._data.seconds=Math.abs(this._data.seconds),this._data.minutes=Math.abs(this._data.minutes),this._data.hours=Math.abs(this._data.hours),this._data.months=Math.abs(this._data.months),this._data.years=Math.abs(this._data.years),this},weeks:function(){return n(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*z(this._months/12)},humanize:function(a){var b=eb(this,!a,this.localeData());return a&&(b=this.localeData().pastFuture(+this,b)),this.localeData().postformat(b)},add:function(a,b){var c=rb.duration(a,b);return this._milliseconds+=c._milliseconds,this._days+=c._days,this._months+=c._months,this._bubble(),this},subtract:function(a,b){var c=rb.duration(a,b);return this._milliseconds-=c._milliseconds,this._days-=c._days,this._months-=c._months,this._bubble(),this},get:function(a){return a=w(a),this[a.toLowerCase()+"s"]()},as:function(a){var b,c;if(a=w(a),b=this._days+this._milliseconds/864e5,"month"===a||"year"===a)return c=this._months+12*nb(b),"month"===a?c:c/12;switch(b+=ob(this._months/12),a){case"week":return b/7;case"day":return b;case"hour":return 24*b;case"minute":return 24*b*60;case"second":return 24*b*60*60;case"millisecond":return 24*b*60*60*1e3;default:throw new Error("Unknown unit "+a)}},lang:rb.fn.lang,locale:rb.fn.locale,toIsoString:e("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var a=Math.abs(this.years()),b=Math.abs(this.months()),c=Math.abs(this.days()),d=Math.abs(this.hours()),e=Math.abs(this.minutes()),f=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"},localeData:function(){return this._locale}});for(tb in fc)fc.hasOwnProperty(tb)&&pb(tb.toLowerCase());rb.duration.fn.asMilliseconds=function(){return this.as("ms")},rb.duration.fn.asSeconds=function(){return this.as("s")},rb.duration.fn.asMinutes=function(){return this.as("m")},rb.duration.fn.asHours=function(){return this.as("h")},rb.duration.fn.asDays=function(){return this.as("d")},rb.duration.fn.asWeeks=function(){return this.as("weeks")},rb.duration.fn.asMonths=function(){return this.as("M")},rb.duration.fn.asYears=function(){return this.as("y")},rb.locale("en",{ordinal:function(a){var b=a%10,c=1===z(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),Gb?module.exports=rb:"function"==typeof define&&define.amd?(define("moment",function(a,b,c){return c.config&&c.config()&&c.config().noGlobal===!0&&(vb.moment=sb),rb}),qb(!0)):qb()}).call(this); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/css/fileinput.min.css b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/css/fileinput.min.css index 3d50954a..924a7fe9 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/css/fileinput.min.css +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/css/fileinput.min.css @@ -1,11 +1,11 @@ -/*! - * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2015 - * @package bootstrap-fileinput - * @version 4.2.3 - * - * File input styling for Bootstrap 3.0 - * Built for Yii Framework 2.0 - * Author: Kartik Visweswaran - * Year: 2015 - * For more Yii related demos visit http://demos.krajee.com +/*! + * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2015 + * @package bootstrap-fileinput + * @version 4.2.3 + * + * File input styling for Bootstrap 3.0 + * Built for Yii Framework 2.0 + * Author: Kartik Visweswaran + * Year: 2015 + * For more Yii related demos visit http://demos.krajee.com */.file-input{overflow-x:auto}.file-loading{top:0;right:0;width:25px;height:25px;font-size:999px;text-align:right;color:#fff;background:transparent url(../image/loading.gif) top left no-repeat;border:none}.btn-file{position:relative;overflow:hidden}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;text-align:right;filter:alpha(opacity=0);opacity:0;background:none repeat scroll 0 0 transparent;cursor:inherit;display:block}.file-caption .glyphicon{display:inline-block;min-width:18px;margin-top:2px}.file-caption-name{display:inline-block;overflow:hidden;max-height:20px;padding-right:10px;word-break:break-all}.file-caption-ellipsis{position:absolute;right:10px;margin-top:-6px;font-size:1.2em;display:none;font-weight:700;cursor:default}.kv-has-ellipsis .file-caption-ellipsis{display:inline}.kv-has-ellipsis{padding-right:17px}.kv-search-container .kv-search-clear{position:absolute;padding:10px;right:0}.file-error-message{background-color:#f2dede;color:#a94442;text-align:center;border-radius:5px;padding:5px}.file-error-message pre,.file-error-message ul{margin:5px 0;text-align:left}.file-caption-disabled{background-color:#EEE;cursor:not-allowed;opacity:1}.file-input .btn .disabled,.file-input .btn[disabled]{cursor:not-allowed}.file-preview{border-radius:5px;border:1px solid #ddd;padding:5px;width:100%;margin-bottom:5px}.file-preview-frame{display:table;margin:8px;height:100px;border:1px solid #ddd;box-shadow:1px 1px 5px 0 #a2958a;padding:6px;float:left;text-align:center;vertical-align:middle}.file-preview-frame:hover{box-shadow:3px 3px 5px 0 #333}.file-preview-image{height:160px;vertical-align:text-center}.file-preview-text{width:160px;color:#428bca;font-size:11px;text-align:center}.file-preview-other{padding-top:20px;text-align:center}.file-preview-other i{font-size:2.4em}.file-other-error{width:100%;padding-top:30px;text-align:right}.file-input-ajax-new .fileinput-remove-button,.file-input-ajax-new .fileinput-upload-button,.file-input-new .close,.file-input-new .file-preview,.file-input-new .fileinput-remove-button,.file-input-new .fileinput-upload-button,.file-input-new .glyphicon-file{display:none}.loading{background:transparent url(../image/loading.gif) no-repeat scroll center center content-box!important}.wrap-indicator{font-weight:700;color:#245269;cursor:pointer}.file-actions{text-align:left}.file-footer-buttons{float:right}.file-thumbnail-footer .file-caption-name{padding-top:4px;font-size:11px;color:#777}.file-upload-indicator{padding-top:2px;cursor:default}.file-upload-indicator:hover{font-size:1.2em;font-weight:700;padding-top:0}.file-drop-zone{border:1px dashed #aaa;border-radius:4px;height:100%;text-align:center;vertical-align:middle;margin:12px 15px 12px 12px;padding:5px}.file-drop-zone-title{color:#aaa;font-size:30px;padding:20px 10px}.highlighted{border:2px dashed #999!important;background-color:#f0f0f0}.file-uploading{background-image:url(../image/loading-sm.gif);background-position:center bottom 10px;background-repeat:no-repeat;opacity:.6}.file-icon-large{font-size:1.2em} \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput.min.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput.min.js index 04a3bca9..efe8633c 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput.min.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput.min.js @@ -1,19 +1,19 @@ -/*! - * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2015 - * @version 4.2.3 - * - * File input styled for Bootstrap 3.0 that utilizes HTML5 File Input's advanced - * features including the FileReader API. - * - * The plugin drastically enhances the HTML file input to preview multiple files on the client before - * upload. In addition it provides the ability to preview content of images, text, videos, audio, html, - * flash and other objects. It also offers the ability to upload and delete files using AJAX, and add - * files in batches (i.e. preview, append, or remove before upload). - * - * Author: Kartik Visweswaran - * Copyright: 2015, Kartik Visweswaran, Krajee.com - * For more JQuery plugins visit http://plugins.krajee.com - * For more Yii related demos visit http://demos.krajee.com - */!function(e){"use strict";e.fn.fileinputLocales={},String.prototype.repl=function(e,i){return this.split(e).join(i)};var i=function(e){var i,t=document.createElement("div");return t.innerHTML="",i=1===t.getElementsByTagName("i").length,document.body.appendChild(t),t.parentNode.removeChild(t),i},t={data:{},init:function(e){var i=e.initialPreview,a=e.id;i.length>0&&!z(i)&&(i=i.split(e.initialPreviewDelimiter)),t.data[a]={content:i,config:e.initialPreviewConfig,tags:e.initialPreviewThumbTags,delimiter:e.initialPreviewDelimiter,template:e.previewGenericTemplate,msg:function(i){return e.getMsgSelected(i)},initId:e.previewInitId,footer:e.getLayoutTemplate("footer"),isDelete:e.initialPreviewShowDelete,caption:e.initialCaption,actions:function(i,t,a,n,r){return e.renderFileActions(i,t,a,n,r)}}},fetch:function(e){return t.data[e].content.filter(function(e){return null!==e})},count:function(e,i){return t.data[e]&&t.data[e].content?i?t.data[e].content.length:t.fetch(e).length:0},get:function(i,a,n){var r,l,o="init_"+a,s=t.data[i],d=s.config[a],c=s.initId+"-"+o,p=" file-preview-initial";return n=void 0===n?!0:n,null===s.content[a]?"":(R(d)||R(d.frameClass)||(p+=" "+d.frameClass),r=s.template.repl("{previewId}",c).repl("{frameClass}",p).repl("{fileindex}",o).repl("{content}",s.content[a]).repl("{footer}",t.footer(i,a,n)),s.tags.length&&s.tags[a]&&(r=H(r,s.tags[a])),R(d)||R(d.frameAttr)||(l=e(document.createElement("div")).html(r),l.find(".file-preview-initial").attr(d.frameAttr),r=l.html(),l.remove()),r)},add:function(i,a,n,r,l){var o,s=e.extend(!0,{},t.data[i]);return z(a)||(a=a.split(s.delimiter)),l?(o=s.content.push(a)-1,s.config[o]=n,s.tags[o]=r):(o=a.length,s.content=a,s.config=n,s.tags=r),t.data[i]=s,o},set:function(i,a,n,r,l){var o,s=e.extend(!0,{},t.data[i]);if(z(a)||(a=a.split(s.delimiter)),l){for(o=0;ol;l++)a+=t.get(e,l);return i=n.msg(t.count(e)),{content:a,caption:i}},footer:function(e,i,a){var n=t.data[e];if(a=void 0===a?!0:a,0===n.config.length||R(n.config[i]))return"";var r=n.config[i],l=M("caption",r)?r.caption:"",o=M("width",r)?r.width:"auto",s=M("url",r)?r.url:!1,d=M("key",r)?r.key:null,c=s===!1&&a,p=n.isDelete?n.actions(!1,!0,c,s,d):"",u=n.footer.repl("{actions}",p);return u.repl("{caption}",l).repl("{width}",o).repl("{indicator}","").repl("{indicatorTitle}","")}},a=function(e,i){return i=i||0,"number"==typeof e?e:("string"==typeof e&&(e=parseFloat(e)),isNaN(e)?i:e)},n=function(){return window.File&&window.FileReader},r=function(){var e=document.createElement("div");return!i(9)&&(void 0!==e.draggable||void 0!==e.ondragstart&&void 0!==e.ondrop)},l=function(){return n()&&window.FormData},o=function(e,i){e.removeClass(i).addClass(i)},s='style="width:{width};height:{height};"',d=' \n \n \n \n \n \n',c='
\n {previewFileIcon}\n
',p={removeIcon:'',removeClass:"btn btn-xs btn-default",removeTitle:"Remove file",uploadIcon:'',uploadClass:"btn btn-xs btn-default",uploadTitle:"Upload file",indicatorNew:'',indicatorSuccess:'',indicatorError:'',indicatorLoading:'',indicatorNewTitle:"Not uploaded yet",indicatorSuccessTitle:"Uploaded",indicatorErrorTitle:"Upload Error",indicatorLoadingTitle:"Uploading ..."},u='{preview}\n
\n
\n {caption}\n
\n {remove}\n {cancel}\n {upload}\n {browse}\n
\n
',f='{preview}\n
\n{remove}\n{cancel}\n{upload}\n{browse}\n',v='
\n
×
\n
\n
\n
\n
\n
\n
\n
',h='',m='
\n \n
\n
',g='',w='
\n
\n {percent}%\n
\n
',b='',x='
\n \n
{indicator}
\n
\n
',C='\n',y='\n',T='
\n {content}\n {footer}\n
\n',E='
\n \n '+c+"\n \n {footer}\n
",k='
\n {caption}\n {footer}\n
\n",F='
\n
\n {data}\n
\n {footer}\n
",$='
\n \n {footer}\n
\n",I='
\n \n {footer}\n
",D='
\n \n'+d+" "+c+"\n \n {footer}\n
\n",P='
\n \n \n'+d+" "+c+"\n \n {footer}\n
",S='
\n "+c+"\n {footer}\n
",U={main1:u,main2:f,preview:v,icon:h,caption:m,modal:g,progress:w,footer:b,actions:x,actionDelete:C,actionUpload:y},j={generic:T,html:E,image:k,text:F,video:$,audio:I,flash:D,object:P,other:S},A=["image","html","text","video","audio","flash","object"],L={image:{width:"auto",height:"160px"},html:{width:"213px",height:"160px"},text:{width:"160px",height:"160px"},video:{width:"213px",height:"160px"},audio:{width:"213px",height:"80px"},flash:{width:"213px",height:"160px"},object:{width:"160px",height:"160px"},other:{width:"160px",height:"160px"}},O={image:function(e,i){return void 0!==e?e.match("image.*"):i.match(/\.(gif|png|jpe?g)$/i)},html:function(e,i){return void 0!==e?"text/html"===e:i.match(/\.(htm|html)$/i)},text:function(e,i){return void 0!==e&&e.match("text.*")||i.match(/\.(txt|md|csv|nfo|php|ini)$/i)},video:function(e,i){return void 0!==e&&e.match(/\.video\/(ogg|mp4|webm)$/i)||i.match(/\.(og?|mp4|webm)$/i)},audio:function(e,i){return void 0!==e&&e.match(/\.audio\/(ogg|mp3|wav)$/i)||i.match(/\.(ogg|mp3|wav)$/i)},flash:function(e,i){return void 0!==e&&"application/x-shockwave-flash"===e||i.match(/\.(swf)$/i)},object:function(){return!0},other:function(){return!0}},R=function(i,t){return null===i||void 0===i||0===i.length||t&&""===e.trim(i)},z=function(e){return Array.isArray(e)||"[object Array]"===Object.prototype.toString.call(e)},M=function(e,i){return"object"==typeof i&&e in i},N=function(i,t,a){return R(i)||R(i[t])?a:e(i[t])},B=function(){return Math.round((new Date).getTime()+100*Math.random())},Z=function(e){return String(e).repl("&","&").repl('"',""").repl("'","'").repl("<","<").repl(">",">")},H=function(i,t){var a=i;return t=t||{},e.each(t,function(e,i){"function"==typeof i&&(i=i()),a=a.repl(e,i)}),a},W=window.URL||window.webkitURL,_=function(t,a){var r=this;r.$element=e(t),r.validate()&&(r.isPreviewable=n(),r.isIE9=i(9),r.isIE10=i(10),r.isPreviewable||r.isIE9?(r.init(a),r.listen()):r.$element.removeClass("file-loading"))};_.prototype={constructor:_,validate:function(){var e,i=this;return"file"===i.$element.attr("type")?!0:(e='

Invalid Input Type

You must set an input type = file for bootstrap-fileinput plugin to initialize.
',i.$element.after(e),!1)},init:function(i){var n,s=this,d=s.$element;e.each(i,function(e,i){s[e]="maxFileCount"===e||"maxFileSize"===e?a(i):i}),s.fileInputCleared=!1,s.fileBatchCompleted=!0,R(s.allowedPreviewTypes)&&(s.allowedPreviewTypes=A),s.isPreviewable||(s.showPreview=!1),s.uploadFileAttr=R(d.attr("name"))?"file_data":d.attr("name"),s.reader=null,s.formdata={},s.filestack=[],s.ajaxRequests=[],s.isError=!1,s.ajaxAborted=!1,s.dropZoneEnabled=r()&&s.dropZoneEnabled,s.isDisabled=s.$element.attr("disabled")||s.$element.attr("readonly"),s.isUploadable=l()&&!R(s.uploadUrl),s.slug="function"==typeof i.slugCallback?i.slugCallback:s.slugDefault,s.mainTemplate=s.getLayoutTemplate(s.showCaption?"main1":"main2"),s.captionTemplate=s.getLayoutTemplate("caption"),s.previewGenericTemplate=s.getPreviewTemplate("generic"),R(s.$element.attr("id"))&&s.$element.attr("id",B()),void 0===s.$container?s.$container=s.createContainer():s.refreshContainer(),s.$progress=s.$container.find(".kv-upload-progress"),s.$btnUpload=s.$container.find(".kv-fileinput-upload"),s.$captionContainer=N(i,"elCaptionContainer",s.$container.find(".file-caption")),s.$caption=N(i,"elCaptionText",s.$container.find(".file-caption-name")),s.$previewContainer=N(i,"elPreviewContainer",s.$container.find(".file-preview")),s.$preview=N(i,"elPreviewImage",s.$container.find(".file-preview-thumbnails")),s.$previewStatus=N(i,"elPreviewStatus",s.$container.find(".file-preview-status")),s.$errorContainer=N(i,"elErrorContainer",s.$previewContainer.find(".kv-fileinput-error")),R(s.msgErrorClass)||o(s.$errorContainer,s.msgErrorClass),s.$errorContainer.hide(),s.fileActionSettings=e.extend(p,i.fileActionSettings),s.previewInitId="preview-"+B(),s.id=s.$element.attr("id"),t.init(s),s.initPreview(!0),s.initPreviewDeletes(),s.options=i,s.setFileDropZoneTitle(),s.uploadCount=0,s.uploadPercent=0,s.$element.removeClass("file-loading"),n=s.getLayoutTemplate("progress"),s.progressTemplate=n.replace("{class}",s.progressClass),s.progressCompleteTemplate=n.replace("{class}",s.progressCompleteClass),s.setEllipsis()},parseError:function(i,t,a){var n=this,r=e.trim(t+""),l="."===r.slice(-1)?"":".",o=void 0!==i.responseJSON&&void 0!==i.responseJSON.error?i.responseJSON.error:i.responseText;return n.showAjaxErrorDetails?(o=e.trim(o.replace(/\n\s*\n/g,"\n")),o=o.length>0?"
"+o+"
":"",r+=l+o):r+=l,a?""+a+": "+i:r},raise:function(i,t){var a=this,n=e.Event(i);if(void 0!==t?a.$element.trigger(n,t):a.$element.trigger(n),!n.result)return n.result;switch(i){case"filebatchuploadcomplete":case"filebatchuploadsuccess":case"fileuploaded":case"fileclear":case"filecleared":case"filereset":case"fileerror":case"filefoldererror":case"fileuploaderror":case"filebatchuploaderror":case"filedeleteerror":case"filecustomerror":case"filesuccessremove":break;default:a.ajaxAborted=n.result}return!0},getLayoutTemplate:function(e){var i=this,t=M(e,i.layoutTemplates)?i.layoutTemplates[e]:U[e];return R(i.customLayoutTags)?t:H(t,i.customLayoutTags)},getPreviewTemplate:function(e){var i=this,t=M(e,i.previewTemplates)?i.previewTemplates[e]:j[e];return t=t.repl("{previewFileIcon}",i.previewFileIcon),R(i.customPreviewTags)?t:H(t,i.customPreviewTags)},getOutData:function(e,i,t){var a=this;return e=e||{},i=i||{},t=t||a.filestack.slice(0)||{},{form:a.formdata,files:t,extra:a.getExtraData(),response:i,reader:a.reader,jqXHR:e}},setEllipsis:function(){var e=this,i=e.$captionContainer,t=e.$caption,a=t.clone().css("height","auto").hide();i.parent().before(a),i.removeClass("kv-has-ellipsis"),a.outerWidth()>t.outerWidth()&&i.addClass("kv-has-ellipsis"),a.remove()},listen:function(){var i=this,t=i.$element,a=i.$captionContainer,n=i.$btnFile,r=t.closest("form");t.on("change",e.proxy(i.change,i)),e(window).on("resize",function(){i.setEllipsis()}),n.off("click").on("click",function(){i.raise("filebrowse"),i.isError&&!i.isUploadable&&i.clear(),a.focus()}),r.off("reset").on("reset",e.proxy(i.reset,i)),i.$container.off("click").on("click",".fileinput-remove:not([disabled])",e.proxy(i.clear,i)).on("click",".fileinput-cancel",e.proxy(i.cancel,i)),i.isUploadable&&i.dropZoneEnabled&&i.showPreview&&i.initDragDrop(),i.isUploadable||r.on("submit",e.proxy(i.submitForm,i)),i.$container.find(".kv-fileinput-upload").off("click").on("click",function(t){var a,n=e(this),r=!n.hasClass("disabled")&&R(n.attr("disabled"));return i.isUploadable?(t.preventDefault(),void(r&&i.upload())):void(r&&"submit"!==n.attr("type")&&(a=n.closest("form"),a.length&&a.trigger("submit"),t.preventDefault()))})},submitForm:function(){var e=this,i=e.$element,t=i.get(0).files;return t&&t.length0?(e.noFilesError({}),!1):!e.abort({})},abort:function(i){var t,a=this;return a.ajaxAborted&&"object"==typeof a.ajaxAborted&&void 0!==a.ajaxAborted.message?(t=e.extend(a.getOutData(),i),t.abortData=a.ajaxAborted.data||{},t.abortMessage=a.ajaxAborted.message,a.showUploadError(a.ajaxAborted.message,t,"filecustomerror"),!0):!1},noFilesError:function(e){var i=this,t=i.minFileCount>1?i.filePlural:i.fileSingle,a=i.msgFilesTooLess.replace("{n}",i.minFileCount).replace("{files}",t),n=i.$errorContainer;n.html(a),i.isError=!0,i.updateFileDetails(0),n.fadeIn(800),i.raise("fileerror",[e]),i.clearFileInput(),o(i.$container,"has-error")},setProgress:function(e){var i=this,t=Math.min(e,100),a=100>t?i.progressTemplate:i.progressCompleteTemplate;R(a)||i.$progress.html(a.repl("{percent}",t))},upload:function(){var i,t,a,n=this,r=n.getFileStack().length,l={},o=!e.isEmptyObject(n.getExtraData());if(r0)return void n.noFilesError(l);if(n.isUploadable&&!n.isDisabled&&(0!==r||o)){if(n.resetUpload(),n.$progress.removeClass("hide"),n.uploadCount=0,n.uploadPercent=0,n.lock(),n.setProgress(0),0===r&&o)return void n.uploadExtraOnly();if(a=n.filestack.length,n.hasInitData=!1,n.uploadAsync&&n.showPreview)for(t=n.getOutData(),n.raise("filebatchpreupload",[t]),n.fileBatchCompleted=!1,n.uploadCache={content:[],config:[],tags:[],append:!0},i=0;a>i;i+=1)void 0!==n.filestack[i]&&n.uploadSingle(i,n.filestack,!0);else n.uploadBatch()}},lock:function(){var e=this;e.resetErrors(),e.disable(),e.showRemove&&o(e.$container.find(".fileinput-remove"),"hide"),e.showCancel&&e.$container.find(".fileinput-cancel").removeClass("hide"),e.raise("filelock",[e.filestack,e.getExtraData()])},unlock:function(e){var i=this;void 0===e&&(e=!0),i.enable(),i.showCancel&&o(i.$container.find(".fileinput-cancel"),"hide"),i.showRemove&&i.$container.find(".fileinput-remove").removeClass("hide"),e&&i.resetFileStack(),i.raise("fileunlock",[i.filestack,i.getExtraData()])},resetFileStack:function(){var i=this,t=0,a=[];i.getThumbs().each(function(){var n=e(this),r=n.attr("data-fileindex"),l=i.filestack[r];-1!==r&&(void 0!==l?(a[t]=l,n.attr({id:i.previewInitId+"-"+t,"data-fileindex":t}),t+=1):n.attr({id:"uploaded-"+B(),"data-fileindex":"-1"}))}),i.filestack=a},refresh:function(i){var t,a=this,n=a.$element,r=arguments.length?e.extend(a.options,i):a.options;n.off(),a.init(r),t=a.$container.find(".file-drop-zone"),t.off("dragenter dragover dragleave drop"),e(document).off("dragenter dragover drop"),a.listen(),a.setFileDropZoneTitle()},initDragDrop:function(){var i=this,t=i.$container.find(".file-drop-zone");t.off("dragenter dragover dragleave drop"),e(document).off("dragenter dragover drop"),t.on("dragenter dragover",function(t){var a=e.inArray("Files",t.originalEvent.dataTransfer.types)>-1;return t.stopPropagation(),t.preventDefault(),i.isDisabled||!a?(t.originalEvent.dataTransfer.effectAllowed="none",void(t.originalEvent.dataTransfer.dropEffect="none")):void o(e(this),"highlighted")}),t.on("dragleave",function(t){t.stopPropagation(),t.preventDefault(),i.isDisabled||e(this).removeClass("highlighted")}),t.on("drop",function(t){t.preventDefault(),i.isDisabled||R(t.originalEvent.dataTransfer.files)||(i.change(t,"dragdrop"),e(this).removeClass("highlighted"))}),e(document).on("dragenter dragover drop",function(e){e.stopPropagation(),e.preventDefault()})},setFileDropZoneTitle:function(){var e=this,i=e.$container.find(".file-drop-zone");i.find("."+e.dropZoneTitleClass).remove(),e.isUploadable&&e.showPreview&&0!==i.length&&!(e.getFileStack().length>0)&&e.dropZoneEnabled&&(0===i.find(".file-preview-frame").length&&i.prepend('
'+e.dropZoneTitle+"
"),e.$container.removeClass("file-input-new"),o(e.$container,"file-input-ajax-new"))},initFileActions:function(){var i=this;i.$preview.find(".kv-file-remove").each(function(){var a,n,r=e(this),l=r.closest(".file-preview-frame"),o=l.attr("data-fileindex");r.off("click").on("click",function(){i.cleanMemory(l),l.fadeOut("slow",function(){i.filestack[o]=void 0,i.clearObjects(l),l.remove();var e=i.getFileStack(!0),r=e.length,s=t.count(i.id);i.clearFileInput(),0===r&&0===s?i.reset():(a=s+r,n=a>1?i.getMsgSelected(a):e[0]?e[0].name:"",i.setCaption(n))})})}),i.$preview.find(".kv-file-upload").each(function(){var t=e(this);t.off("click").on("click",function(){var e=t.closest(".file-preview-frame"),a=e.attr("data-fileindex");i.uploadSingle(a,i.filestack,!1)})})},getMsgSelected:function(e){var i=this,t=1===e?i.fileSingle:i.filePlural;return i.msgSelected.replace("{n}",e).replace("{files}",t)},renderFileFooter:function(e,i){var t,a,n=this,r=n.fileActionSettings,l=n.getLayoutTemplate("footer");return n.isUploadable?(t=l.repl("{actions}",n.renderFileActions(!0,!0,!1,!1,!1)),a=t.repl("{caption}",e).repl("{width}",i).repl("{indicator}",r.indicatorNew).repl("{indicatorTitle}",r.indicatorNewTitle)):a=l.repl("{actions}","").repl("{caption}",e).repl("{width}",i).repl("{indicator}","").repl("{indicatorTitle}",""),a=H(a,n.previewThumbTags)},renderFileActions:function(e,i,t,a,n){if(!e&&!i)return"";var r=this,l=a===!1?"":' data-url="'+a+'"',o=n===!1?"":' data-key="'+n+'"',s=r.getLayoutTemplate("actionDelete"),d="",c=r.getLayoutTemplate("actions"),p=r.otherActionButtons.repl("{dataKey}",o),u=r.fileActionSettings,f=t?u.removeClass+" disabled":u.removeClass;return s=s.repl("{removeClass}",f).repl("{removeIcon}",u.removeIcon).repl("{removeTitle}",u.removeTitle).repl("{dataUrl}",l).repl("{dataKey}",o),e&&(d=r.getLayoutTemplate("actionUpload").repl("{uploadClass}",u.uploadClass).repl("{uploadIcon}",u.uploadIcon).repl("{uploadTitle}",u.uploadTitle)),c.repl("{delete}",s).repl("{upload}",d).repl("{other}",p)},setThumbStatus:function(e,i){var t=this,a="indicator"+i,n=a+"Title",r="file-preview-"+i.toLowerCase(),l=e.find(".file-upload-indicator"),o=t.fileActionSettings;e.removeClass("file-preview-success file-preview-error file-preview-loading"),l.html(o[a]),l.attr("title",o[n]),e.addClass(r)},clearPreview:function(){var e=this,i=e.$preview.find(e.showUploadedThumbs?".file-preview-frame:not(.file-preview-success)":".file-preview-frame");i.remove(),e.$preview.find(".file-preview-frame").length&&e.showPreview||e.resetUpload()},initPreview:function(e){var i,a=this,n=a.initialCaption||"";return t.count(a.id)?(i=t.out(a.id),n=e&&a.initialCaption?a.initialCaption:i.caption,a.$preview.html(i.content),a.setCaption(n),void(R(i.content)||a.$container.removeClass("file-input-new"))):(a.clearPreview(),void(e?a.setCaption(n):a.initCaption()))},initPreviewDeletes:function(){var i=this,a=i.deleteExtraData||{},n=function(){0===i.$preview.find(".kv-file-remove").length&&(i.reset(),i.initialCaption="")};i.$preview.find(".kv-file-remove").each(function(){var r=e(this),l=r.data("url")||i.deleteUrl,s=r.data("key");if(!R(l)&&void 0!==s){var d,c,p,u,f=r.closest(".file-preview-frame"),v=t.data[i.id],h=f.data("fileindex");h=parseInt(h.replace("init_","")),p=R(v.config)&&R(v.config[h])?null:v.config[h],u=R(p)||R(p.extra)?a:p.extra,"function"==typeof u&&(u=u()),c={id:r.attr("id"),key:s,extra:u},d=e.extend({url:l,type:"DELETE",dataType:"json",data:e.extend({key:s},u),beforeSend:function(e){i.ajaxAborted=!1,i.raise("filepredelete",[s,e,u]),i.ajaxAborted?e.abort():(o(f,"file-uploading"),o(r,"disabled"))},success:function(e,a,l){var o,d;return R(e)||R(e.error)?(t.unset(i.id,h),o=t.count(i.id),d=o>0?i.getMsgSelected(o):"",i.raise("filedeleted",[s,l,u]),i.setCaption(d),f.removeClass("file-uploading").addClass("file-deleted"),void f.fadeOut("slow",function(){i.clearObjects(f),f.remove(),n(),o||0!==i.getFileStack().length||(i.setCaption(""),i.reset())})):(c.jqXHR=l,c.response=e,i.showError(e.error,c,"filedeleteerror"),f.removeClass("file-uploading"),r.removeClass("disabled"),void n())},error:function(e,t,a){var r=i.parseError(e,a);c.jqXHR=e,c.response={},i.showError(r,c,"filedeleteerror"),f.removeClass("file-uploading"),n()}},i.ajaxDeleteSettings),r.off("click").on("click",function(){e.ajax(d)})}})},clearObjects:function(i){i.find("video audio").each(function(){this.pause(),e(this).remove()}),i.find("img object div").each(function(){e(this).remove()})},clearFileInput:function(){var i,t,a,n=this,r=n.$element;R(r.val())||(n.isIE9||n.isIE10?(i=r.closest("form"),t=e(document.createElement("form")),a=e(document.createElement("div")),r.before(a),i.length?i.after(t):a.after(t),t.append(r).trigger("reset"),a.before(r).remove(),t.remove()):r.val(""),n.fileInputCleared=!0)},resetUpload:function(){var e=this;e.uploadCache={content:[],config:[],tags:[],append:!0},e.uploadCount=0,e.uploadPercent=0,e.$btnUpload.removeAttr("disabled"),e.setProgress(0),o(e.$progress,"hide"),e.resetErrors(!1),e.ajaxAborted=!1,e.ajaxRequests=[]},cancel:function(){var i,t=this,a=t.ajaxRequests,n=a.length;if(n>0)for(i=0;n>i;i+=1)a[i].abort();t.getThumbs().each(function(){var i=e(this),a=i.attr("data-fileindex");i.removeClass("file-uploading"),void 0!==t.filestack[a]&&(i.find(".kv-file-upload").removeClass("disabled").removeAttr("disabled"),i.find(".kv-file-remove").removeClass("disabled").removeAttr("disabled")),t.unlock()})},cleanMemory:function(e){var i=e.is("img")?e.attr("src"):e.find("source").attr("src");W.revokeObjectURL(i)},hasInitialPreview:function(){var e=this;return!e.overwriteInitial&&t.count(e.id)},clear:function(){var i,t=this;t.$btnUpload.removeAttr("disabled"),t.getThumbs().find("video,audio,img").each(function(){t.cleanMemory(e(this))}),t.resetUpload(),t.filestack=[],t.clearFileInput(),t.resetErrors(!0),t.raise("fileclear"),t.hasInitialPreview()?(t.showFileIcon(),t.resetPreview(),t.setEllipsis(),t.initPreviewDeletes(),t.$container.removeClass("file-input-new")):(t.getThumbs().each(function(){t.clearObjects(e(this))}),t.$preview.html(""),i=!t.overwriteInitial&&t.initialCaption.length>0?t.initialCaption:"",t.setCaption(i),t.setEllipsis(),t.$caption.attr("title",""),o(t.$container,"file-input-new")),0===t.$container.find(".file-preview-frame").length&&(t.initCaption()||t.$captionContainer.find(".kv-caption-icon").hide(),t.setEllipsis()),t.hideFileIcon(),t.raise("filecleared"),t.$captionContainer.focus(),t.setFileDropZoneTitle()},resetPreview:function(){var e,i=this;t.count(i.id)?(e=t.out(i.id),i.$preview.html(e.content),i.setCaption(e.caption)):(i.clearPreview(),i.initCaption())},reset:function(){var e=this;e.resetPreview(),e.setEllipsis(),e.$container.find(".fileinput-filename").text(""),e.raise("filereset"),e.initialPreview.length>0&&e.$container.removeClass("file-input-new"),e.setFileDropZoneTitle(),e.filestack=[],e.formdata={}},disable:function(){var e=this;e.isDisabled=!0,e.raise("filedisabled"),e.$element.attr("disabled","disabled"),e.$container.find(".kv-fileinput-caption").addClass("file-caption-disabled"),e.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload").attr("disabled",!0),e.initDragDrop()},enable:function(){var e=this;e.isDisabled=!1,e.raise("fileenabled"),e.$element.removeAttr("disabled"),e.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled"),e.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload").removeAttr("disabled"),e.initDragDrop()},getThumbs:function(e){return e=e||"",this.$preview.find(".file-preview-frame:not(.file-preview-initial)"+e)},getExtraData:function(){var e=this,i=e.uploadExtraData;return"function"==typeof e.uploadExtraData&&(i=e.uploadExtraData()),i},uploadExtra:function(){var i=this,t=i.getExtraData();0!==t.length&&e.each(t,function(e,t){i.formdata.append(e,t)})},initXhr:function(e,i){var t=this;return e.upload&&e.upload.addEventListener("progress",function(e){var a=0,n=e.loaded||e.position,r=e.total;e.lengthComputable&&(a=Math.ceil(n/r*i)),t.uploadPercent=Math.max(a,t.uploadPercent),t.setProgress(t.uploadPercent)},!1),e},ajaxSubmit:function(i,t,a,n){var r,l=this;l.uploadExtra(),r=e.extend({xhr:function(){var i=e.ajaxSettings.xhr();return l.initXhr(i,98)},url:l.uploadUrl,type:"POST",dataType:"json",data:l.formdata,cache:!1,processData:!1,contentType:!1,beforeSend:i,success:t,complete:a,error:n},l.ajaxSettings),l.ajaxRequests.push(e.ajax(r))},initUploadSuccess:function(i,a,n){var r,l,o,s,d,c,p,u=this;"object"!=typeof i||e.isEmptyObject(i)||void 0!==i.initialPreview&&i.initialPreview.length>0&&(u.hasInitData=!0,d=i.initialPreview||[],c=i.initialPreviewConfig||[],p=i.initialPreviewThumbTags||[],r=void 0===i.append||i.append?!0:!1,u.overwriteInitial=!1,void 0===a||n?n?(u.uploadCache.content.push(d[0]),u.uploadCache.config.push(c[0]),u.uploadCache.tags.push(p[0]),u.uploadCache.append=r):(t.set(u.id,d,c,p,r),u.initPreview(),u.initPreviewDeletes()):(o=t.add(u.id,d,c[0],p[0],r),l=t.get(u.id,o,!1),s=e(l).hide(),a.after(s).fadeOut("slow",function(){s.fadeIn("slow").css("display:inline-block"),u.initPreviewDeletes(),u.clearFileInput(),a.remove()})))},initSuccessThumbs:function(){var i=this;i.getThumbs(".file-preview-success").each(function(){var t=e(this),a=t.find(".kv-file-remove");a.removeAttr("disabled").off("click").on("click",function(){var e=i.raise("filesuccessremove",[t.attr("id"),t.data("fileindex")]);i.cleanMemory(t),e!==!1&&t.fadeOut("slow",function(){t.remove(),i.$preview.find(".file-preview-frame").length||i.reset()})})})},uploadSingle:function(i,a,n){var r,l,s,d,c,p,u,f,v,h=this,m=h.getFileStack().length,g=new FormData,w=h.previewInitId+"-"+i,b=e("#"+w+":not(.file-preview-initial)"),x=b.find(".kv-file-upload"),C=b.find(".kv-file-remove"),y=h.filestack.length>0||!e.isEmptyObject(h.uploadExtraData),T={id:w,index:i};h.formdata=g,0===m||!y||x.hasClass("disabled")||h.abort(T)||(s=function(){var e=h.getThumbs(".file-uploading");e.length>0||h.fileBatchCompleted||(h.fileBatchCompleted=!0,setTimeout(function(){t.set(h.id,h.uploadCache.content,h.uploadCache.config,h.uploadCache.tags,h.uploadCache.append),h.hasInitData&&(h.initPreview(),h.initPreviewDeletes()),h.setProgress(100),h.unlock(),h.clearFileInput(),h.raise("filebatchuploadcomplete",[h.filestack,h.getExtraData()])},100))},d=function(){!n||0===m||h.uploadPercent>=100||(h.uploadCount+=1,l=80+Math.ceil(20*h.uploadCount/m),h.uploadPercent=Math.max(l,h.uploadPercent),h.setProgress(h.uploadPercent),h.initPreviewDeletes())},c=function(){x.removeAttr("disabled"),C.removeAttr("disabled"),b.removeClass("file-uploading")},p=function(t){r=h.getOutData(t),b.hasClass("file-preview-success")||(h.setThumbStatus(b,"Loading"),o(b,"file-uploading")),x.attr("disabled",!0),C.attr("disabled",!0),n||h.lock(),h.raise("filepreupload",[r,w,i]),T=e.extend(T,r),h.abort(T)&&(t.abort(),h.setProgress(100))},u=function(t,a,l){r=h.getOutData(l,t),T=e.extend(T,r),setTimeout(function(){R(t)||R(t.error)?(h.setThumbStatus(b,"Success"),x.hide(),h.filestack[i]=void 0,h.raise("fileuploaded",[r,w,i]),h.initUploadSuccess(t,b,n),n||h.resetFileStack()):(h.setThumbStatus(b,"Error"),h.showUploadError(t.error,T))},100)},f=function(){setTimeout(function(){d(),c(),n?s():h.unlock(!1),h.initSuccessThumbs()},100)},v=function(t,r,l){var o=h.parseError(t,l,n?a[i].name:null);h.setThumbStatus(b,"Error"),T=e.extend(T,h.getOutData(t)),h.showUploadError(o,T)},g.append(h.uploadFileAttr,a[i]),g.append("file_id",i),h.ajaxSubmit(p,u,f,v))},uploadBatch:function(){var i,t,a,n,r,l=this,s=l.filestack,d=s.length,c=l.filestack.length>0||!e.isEmptyObject(l.uploadExtraData),p={};l.formdata=new FormData,0!==d&&c&&!l.abort(p)&&(i=function(){e.each(s,function(e){l.filestack[e]=void 0}),l.clearFileInput()},t=function(i){l.lock();var t=l.getOutData(i);l.showPreview&&l.getThumbs().each(function(){var i=e(this),t=i.find(".kv-file-upload"),a=i.find(".kv-file-remove");i.hasClass("file-preview-success")||(l.setThumbStatus(i,"Loading"),o(i,"file-uploading")),t.attr("disabled",!0),a.attr("disabled",!0)}),l.raise("filebatchpreupload",[t]),l.abort(t)&&i.abort()},a=function(t,a,n){var r=l.getOutData(n,t),o=l.getThumbs(),s=R(t.errorkeys)?[]:t.errorkeys;R(t)||R(t.error)?(l.raise("filebatchuploadsuccess",[r]),i(),l.showPreview?(o.each(function(){var i=e(this),t=i.find(".kv-file-upload");i.find(".kv-file-upload").hide(),l.setThumbStatus(i,"Success"),i.removeClass("file-uploading"),t.removeAttr("disabled")}),l.initUploadSuccess(t)):l.reset()):(l.showPreview&&(o.each(function(){var i=e(this),t=i.find(".kv-file-remove"),a=i.find(".kv-file-upload");return i.removeClass("file-uploading"),a.removeAttr("disabled"),t.removeAttr("disabled"),0===s.length?void l.setThumbStatus(i,"Error"):void(-1!==e.inArray(key,s)?l.setThumbStatus(i,"Error"):(i.find(".kv-file-upload").hide(),l.setThumbStatus(i,"Success"),l.filestack[key]=void 0)); - +/*! + * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2015 + * @version 4.2.3 + * + * File input styled for Bootstrap 3.0 that utilizes HTML5 File Input's advanced + * features including the FileReader API. + * + * The plugin drastically enhances the HTML file input to preview multiple files on the client before + * upload. In addition it provides the ability to preview content of images, text, videos, audio, html, + * flash and other objects. It also offers the ability to upload and delete files using AJAX, and add + * files in batches (i.e. preview, append, or remove before upload). + * + * Author: Kartik Visweswaran + * Copyright: 2015, Kartik Visweswaran, Krajee.com + * For more JQuery plugins visit http://plugins.krajee.com + * For more Yii related demos visit http://demos.krajee.com + */!function(e){"use strict";e.fn.fileinputLocales={},String.prototype.repl=function(e,i){return this.split(e).join(i)};var i=function(e){var i,t=document.createElement("div");return t.innerHTML="",i=1===t.getElementsByTagName("i").length,document.body.appendChild(t),t.parentNode.removeChild(t),i},t={data:{},init:function(e){var i=e.initialPreview,a=e.id;i.length>0&&!z(i)&&(i=i.split(e.initialPreviewDelimiter)),t.data[a]={content:i,config:e.initialPreviewConfig,tags:e.initialPreviewThumbTags,delimiter:e.initialPreviewDelimiter,template:e.previewGenericTemplate,msg:function(i){return e.getMsgSelected(i)},initId:e.previewInitId,footer:e.getLayoutTemplate("footer"),isDelete:e.initialPreviewShowDelete,caption:e.initialCaption,actions:function(i,t,a,n,r){return e.renderFileActions(i,t,a,n,r)}}},fetch:function(e){return t.data[e].content.filter(function(e){return null!==e})},count:function(e,i){return t.data[e]&&t.data[e].content?i?t.data[e].content.length:t.fetch(e).length:0},get:function(i,a,n){var r,l,o="init_"+a,s=t.data[i],d=s.config[a],c=s.initId+"-"+o,p=" file-preview-initial";return n=void 0===n?!0:n,null===s.content[a]?"":(R(d)||R(d.frameClass)||(p+=" "+d.frameClass),r=s.template.repl("{previewId}",c).repl("{frameClass}",p).repl("{fileindex}",o).repl("{content}",s.content[a]).repl("{footer}",t.footer(i,a,n)),s.tags.length&&s.tags[a]&&(r=H(r,s.tags[a])),R(d)||R(d.frameAttr)||(l=e(document.createElement("div")).html(r),l.find(".file-preview-initial").attr(d.frameAttr),r=l.html(),l.remove()),r)},add:function(i,a,n,r,l){var o,s=e.extend(!0,{},t.data[i]);return z(a)||(a=a.split(s.delimiter)),l?(o=s.content.push(a)-1,s.config[o]=n,s.tags[o]=r):(o=a.length,s.content=a,s.config=n,s.tags=r),t.data[i]=s,o},set:function(i,a,n,r,l){var o,s=e.extend(!0,{},t.data[i]);if(z(a)||(a=a.split(s.delimiter)),l){for(o=0;ol;l++)a+=t.get(e,l);return i=n.msg(t.count(e)),{content:a,caption:i}},footer:function(e,i,a){var n=t.data[e];if(a=void 0===a?!0:a,0===n.config.length||R(n.config[i]))return"";var r=n.config[i],l=M("caption",r)?r.caption:"",o=M("width",r)?r.width:"auto",s=M("url",r)?r.url:!1,d=M("key",r)?r.key:null,c=s===!1&&a,p=n.isDelete?n.actions(!1,!0,c,s,d):"",u=n.footer.repl("{actions}",p);return u.repl("{caption}",l).repl("{width}",o).repl("{indicator}","").repl("{indicatorTitle}","")}},a=function(e,i){return i=i||0,"number"==typeof e?e:("string"==typeof e&&(e=parseFloat(e)),isNaN(e)?i:e)},n=function(){return window.File&&window.FileReader},r=function(){var e=document.createElement("div");return!i(9)&&(void 0!==e.draggable||void 0!==e.ondragstart&&void 0!==e.ondrop)},l=function(){return n()&&window.FormData},o=function(e,i){e.removeClass(i).addClass(i)},s='style="width:{width};height:{height};"',d=' \n \n \n \n \n \n',c='
\n {previewFileIcon}\n
',p={removeIcon:'',removeClass:"btn btn-xs btn-default",removeTitle:"Remove file",uploadIcon:'',uploadClass:"btn btn-xs btn-default",uploadTitle:"Upload file",indicatorNew:'',indicatorSuccess:'',indicatorError:'',indicatorLoading:'',indicatorNewTitle:"Not uploaded yet",indicatorSuccessTitle:"Uploaded",indicatorErrorTitle:"Upload Error",indicatorLoadingTitle:"Uploading ..."},u='{preview}\n
\n
\n {caption}\n
\n {remove}\n {cancel}\n {upload}\n {browse}\n
\n
',f='{preview}\n
\n{remove}\n{cancel}\n{upload}\n{browse}\n',v='
\n
×
\n
\n
\n
\n
\n
\n
\n
',h='',m='
\n \n
\n
',g='',w='
\n
\n {percent}%\n
\n
',b='',x='
\n \n
{indicator}
\n
\n
',C='\n',y='\n',T='
\n {content}\n {footer}\n
\n',E='
\n \n '+c+"\n \n {footer}\n
",k='
\n {caption}\n {footer}\n
\n",F='
\n
\n {data}\n
\n {footer}\n
",$='
\n \n {footer}\n
\n",I='
\n \n {footer}\n
",D='
\n \n'+d+" "+c+"\n \n {footer}\n
\n",P='
\n \n \n'+d+" "+c+"\n \n {footer}\n
",S='
\n "+c+"\n {footer}\n
",U={main1:u,main2:f,preview:v,icon:h,caption:m,modal:g,progress:w,footer:b,actions:x,actionDelete:C,actionUpload:y},j={generic:T,html:E,image:k,text:F,video:$,audio:I,flash:D,object:P,other:S},A=["image","html","text","video","audio","flash","object"],L={image:{width:"auto",height:"160px"},html:{width:"213px",height:"160px"},text:{width:"160px",height:"160px"},video:{width:"213px",height:"160px"},audio:{width:"213px",height:"80px"},flash:{width:"213px",height:"160px"},object:{width:"160px",height:"160px"},other:{width:"160px",height:"160px"}},O={image:function(e,i){return void 0!==e?e.match("image.*"):i.match(/\.(gif|png|jpe?g)$/i)},html:function(e,i){return void 0!==e?"text/html"===e:i.match(/\.(htm|html)$/i)},text:function(e,i){return void 0!==e&&e.match("text.*")||i.match(/\.(txt|md|csv|nfo|php|ini)$/i)},video:function(e,i){return void 0!==e&&e.match(/\.video\/(ogg|mp4|webm)$/i)||i.match(/\.(og?|mp4|webm)$/i)},audio:function(e,i){return void 0!==e&&e.match(/\.audio\/(ogg|mp3|wav)$/i)||i.match(/\.(ogg|mp3|wav)$/i)},flash:function(e,i){return void 0!==e&&"application/x-shockwave-flash"===e||i.match(/\.(swf)$/i)},object:function(){return!0},other:function(){return!0}},R=function(i,t){return null===i||void 0===i||0===i.length||t&&""===e.trim(i)},z=function(e){return Array.isArray(e)||"[object Array]"===Object.prototype.toString.call(e)},M=function(e,i){return"object"==typeof i&&e in i},N=function(i,t,a){return R(i)||R(i[t])?a:e(i[t])},B=function(){return Math.round((new Date).getTime()+100*Math.random())},Z=function(e){return String(e).repl("&","&").repl('"',""").repl("'","'").repl("<","<").repl(">",">")},H=function(i,t){var a=i;return t=t||{},e.each(t,function(e,i){"function"==typeof i&&(i=i()),a=a.repl(e,i)}),a},W=window.URL||window.webkitURL,_=function(t,a){var r=this;r.$element=e(t),r.validate()&&(r.isPreviewable=n(),r.isIE9=i(9),r.isIE10=i(10),r.isPreviewable||r.isIE9?(r.init(a),r.listen()):r.$element.removeClass("file-loading"))};_.prototype={constructor:_,validate:function(){var e,i=this;return"file"===i.$element.attr("type")?!0:(e='

Invalid Input Type

You must set an input type = file for bootstrap-fileinput plugin to initialize.
',i.$element.after(e),!1)},init:function(i){var n,s=this,d=s.$element;e.each(i,function(e,i){s[e]="maxFileCount"===e||"maxFileSize"===e?a(i):i}),s.fileInputCleared=!1,s.fileBatchCompleted=!0,R(s.allowedPreviewTypes)&&(s.allowedPreviewTypes=A),s.isPreviewable||(s.showPreview=!1),s.uploadFileAttr=R(d.attr("name"))?"file_data":d.attr("name"),s.reader=null,s.formdata={},s.filestack=[],s.ajaxRequests=[],s.isError=!1,s.ajaxAborted=!1,s.dropZoneEnabled=r()&&s.dropZoneEnabled,s.isDisabled=s.$element.attr("disabled")||s.$element.attr("readonly"),s.isUploadable=l()&&!R(s.uploadUrl),s.slug="function"==typeof i.slugCallback?i.slugCallback:s.slugDefault,s.mainTemplate=s.getLayoutTemplate(s.showCaption?"main1":"main2"),s.captionTemplate=s.getLayoutTemplate("caption"),s.previewGenericTemplate=s.getPreviewTemplate("generic"),R(s.$element.attr("id"))&&s.$element.attr("id",B()),void 0===s.$container?s.$container=s.createContainer():s.refreshContainer(),s.$progress=s.$container.find(".kv-upload-progress"),s.$btnUpload=s.$container.find(".kv-fileinput-upload"),s.$captionContainer=N(i,"elCaptionContainer",s.$container.find(".file-caption")),s.$caption=N(i,"elCaptionText",s.$container.find(".file-caption-name")),s.$previewContainer=N(i,"elPreviewContainer",s.$container.find(".file-preview")),s.$preview=N(i,"elPreviewImage",s.$container.find(".file-preview-thumbnails")),s.$previewStatus=N(i,"elPreviewStatus",s.$container.find(".file-preview-status")),s.$errorContainer=N(i,"elErrorContainer",s.$previewContainer.find(".kv-fileinput-error")),R(s.msgErrorClass)||o(s.$errorContainer,s.msgErrorClass),s.$errorContainer.hide(),s.fileActionSettings=e.extend(p,i.fileActionSettings),s.previewInitId="preview-"+B(),s.id=s.$element.attr("id"),t.init(s),s.initPreview(!0),s.initPreviewDeletes(),s.options=i,s.setFileDropZoneTitle(),s.uploadCount=0,s.uploadPercent=0,s.$element.removeClass("file-loading"),n=s.getLayoutTemplate("progress"),s.progressTemplate=n.replace("{class}",s.progressClass),s.progressCompleteTemplate=n.replace("{class}",s.progressCompleteClass),s.setEllipsis()},parseError:function(i,t,a){var n=this,r=e.trim(t+""),l="."===r.slice(-1)?"":".",o=void 0!==i.responseJSON&&void 0!==i.responseJSON.error?i.responseJSON.error:i.responseText;return n.showAjaxErrorDetails?(o=e.trim(o.replace(/\n\s*\n/g,"\n")),o=o.length>0?"
"+o+"
":"",r+=l+o):r+=l,a?""+a+": "+i:r},raise:function(i,t){var a=this,n=e.Event(i);if(void 0!==t?a.$element.trigger(n,t):a.$element.trigger(n),!n.result)return n.result;switch(i){case"filebatchuploadcomplete":case"filebatchuploadsuccess":case"fileuploaded":case"fileclear":case"filecleared":case"filereset":case"fileerror":case"filefoldererror":case"fileuploaderror":case"filebatchuploaderror":case"filedeleteerror":case"filecustomerror":case"filesuccessremove":break;default:a.ajaxAborted=n.result}return!0},getLayoutTemplate:function(e){var i=this,t=M(e,i.layoutTemplates)?i.layoutTemplates[e]:U[e];return R(i.customLayoutTags)?t:H(t,i.customLayoutTags)},getPreviewTemplate:function(e){var i=this,t=M(e,i.previewTemplates)?i.previewTemplates[e]:j[e];return t=t.repl("{previewFileIcon}",i.previewFileIcon),R(i.customPreviewTags)?t:H(t,i.customPreviewTags)},getOutData:function(e,i,t){var a=this;return e=e||{},i=i||{},t=t||a.filestack.slice(0)||{},{form:a.formdata,files:t,extra:a.getExtraData(),response:i,reader:a.reader,jqXHR:e}},setEllipsis:function(){var e=this,i=e.$captionContainer,t=e.$caption,a=t.clone().css("height","auto").hide();i.parent().before(a),i.removeClass("kv-has-ellipsis"),a.outerWidth()>t.outerWidth()&&i.addClass("kv-has-ellipsis"),a.remove()},listen:function(){var i=this,t=i.$element,a=i.$captionContainer,n=i.$btnFile,r=t.closest("form");t.on("change",e.proxy(i.change,i)),e(window).on("resize",function(){i.setEllipsis()}),n.off("click").on("click",function(){i.raise("filebrowse"),i.isError&&!i.isUploadable&&i.clear(),a.focus()}),r.off("reset").on("reset",e.proxy(i.reset,i)),i.$container.off("click").on("click",".fileinput-remove:not([disabled])",e.proxy(i.clear,i)).on("click",".fileinput-cancel",e.proxy(i.cancel,i)),i.isUploadable&&i.dropZoneEnabled&&i.showPreview&&i.initDragDrop(),i.isUploadable||r.on("submit",e.proxy(i.submitForm,i)),i.$container.find(".kv-fileinput-upload").off("click").on("click",function(t){var a,n=e(this),r=!n.hasClass("disabled")&&R(n.attr("disabled"));return i.isUploadable?(t.preventDefault(),void(r&&i.upload())):void(r&&"submit"!==n.attr("type")&&(a=n.closest("form"),a.length&&a.trigger("submit"),t.preventDefault()))})},submitForm:function(){var e=this,i=e.$element,t=i.get(0).files;return t&&t.length0?(e.noFilesError({}),!1):!e.abort({})},abort:function(i){var t,a=this;return a.ajaxAborted&&"object"==typeof a.ajaxAborted&&void 0!==a.ajaxAborted.message?(t=e.extend(a.getOutData(),i),t.abortData=a.ajaxAborted.data||{},t.abortMessage=a.ajaxAborted.message,a.showUploadError(a.ajaxAborted.message,t,"filecustomerror"),!0):!1},noFilesError:function(e){var i=this,t=i.minFileCount>1?i.filePlural:i.fileSingle,a=i.msgFilesTooLess.replace("{n}",i.minFileCount).replace("{files}",t),n=i.$errorContainer;n.html(a),i.isError=!0,i.updateFileDetails(0),n.fadeIn(800),i.raise("fileerror",[e]),i.clearFileInput(),o(i.$container,"has-error")},setProgress:function(e){var i=this,t=Math.min(e,100),a=100>t?i.progressTemplate:i.progressCompleteTemplate;R(a)||i.$progress.html(a.repl("{percent}",t))},upload:function(){var i,t,a,n=this,r=n.getFileStack().length,l={},o=!e.isEmptyObject(n.getExtraData());if(r0)return void n.noFilesError(l);if(n.isUploadable&&!n.isDisabled&&(0!==r||o)){if(n.resetUpload(),n.$progress.removeClass("hide"),n.uploadCount=0,n.uploadPercent=0,n.lock(),n.setProgress(0),0===r&&o)return void n.uploadExtraOnly();if(a=n.filestack.length,n.hasInitData=!1,n.uploadAsync&&n.showPreview)for(t=n.getOutData(),n.raise("filebatchpreupload",[t]),n.fileBatchCompleted=!1,n.uploadCache={content:[],config:[],tags:[],append:!0},i=0;a>i;i+=1)void 0!==n.filestack[i]&&n.uploadSingle(i,n.filestack,!0);else n.uploadBatch()}},lock:function(){var e=this;e.resetErrors(),e.disable(),e.showRemove&&o(e.$container.find(".fileinput-remove"),"hide"),e.showCancel&&e.$container.find(".fileinput-cancel").removeClass("hide"),e.raise("filelock",[e.filestack,e.getExtraData()])},unlock:function(e){var i=this;void 0===e&&(e=!0),i.enable(),i.showCancel&&o(i.$container.find(".fileinput-cancel"),"hide"),i.showRemove&&i.$container.find(".fileinput-remove").removeClass("hide"),e&&i.resetFileStack(),i.raise("fileunlock",[i.filestack,i.getExtraData()])},resetFileStack:function(){var i=this,t=0,a=[];i.getThumbs().each(function(){var n=e(this),r=n.attr("data-fileindex"),l=i.filestack[r];-1!==r&&(void 0!==l?(a[t]=l,n.attr({id:i.previewInitId+"-"+t,"data-fileindex":t}),t+=1):n.attr({id:"uploaded-"+B(),"data-fileindex":"-1"}))}),i.filestack=a},refresh:function(i){var t,a=this,n=a.$element,r=arguments.length?e.extend(a.options,i):a.options;n.off(),a.init(r),t=a.$container.find(".file-drop-zone"),t.off("dragenter dragover dragleave drop"),e(document).off("dragenter dragover drop"),a.listen(),a.setFileDropZoneTitle()},initDragDrop:function(){var i=this,t=i.$container.find(".file-drop-zone");t.off("dragenter dragover dragleave drop"),e(document).off("dragenter dragover drop"),t.on("dragenter dragover",function(t){var a=e.inArray("Files",t.originalEvent.dataTransfer.types)>-1;return t.stopPropagation(),t.preventDefault(),i.isDisabled||!a?(t.originalEvent.dataTransfer.effectAllowed="none",void(t.originalEvent.dataTransfer.dropEffect="none")):void o(e(this),"highlighted")}),t.on("dragleave",function(t){t.stopPropagation(),t.preventDefault(),i.isDisabled||e(this).removeClass("highlighted")}),t.on("drop",function(t){t.preventDefault(),i.isDisabled||R(t.originalEvent.dataTransfer.files)||(i.change(t,"dragdrop"),e(this).removeClass("highlighted"))}),e(document).on("dragenter dragover drop",function(e){e.stopPropagation(),e.preventDefault()})},setFileDropZoneTitle:function(){var e=this,i=e.$container.find(".file-drop-zone");i.find("."+e.dropZoneTitleClass).remove(),e.isUploadable&&e.showPreview&&0!==i.length&&!(e.getFileStack().length>0)&&e.dropZoneEnabled&&(0===i.find(".file-preview-frame").length&&i.prepend('
'+e.dropZoneTitle+"
"),e.$container.removeClass("file-input-new"),o(e.$container,"file-input-ajax-new"))},initFileActions:function(){var i=this;i.$preview.find(".kv-file-remove").each(function(){var a,n,r=e(this),l=r.closest(".file-preview-frame"),o=l.attr("data-fileindex");r.off("click").on("click",function(){i.cleanMemory(l),l.fadeOut("slow",function(){i.filestack[o]=void 0,i.clearObjects(l),l.remove();var e=i.getFileStack(!0),r=e.length,s=t.count(i.id);i.clearFileInput(),0===r&&0===s?i.reset():(a=s+r,n=a>1?i.getMsgSelected(a):e[0]?e[0].name:"",i.setCaption(n))})})}),i.$preview.find(".kv-file-upload").each(function(){var t=e(this);t.off("click").on("click",function(){var e=t.closest(".file-preview-frame"),a=e.attr("data-fileindex");i.uploadSingle(a,i.filestack,!1)})})},getMsgSelected:function(e){var i=this,t=1===e?i.fileSingle:i.filePlural;return i.msgSelected.replace("{n}",e).replace("{files}",t)},renderFileFooter:function(e,i){var t,a,n=this,r=n.fileActionSettings,l=n.getLayoutTemplate("footer");return n.isUploadable?(t=l.repl("{actions}",n.renderFileActions(!0,!0,!1,!1,!1)),a=t.repl("{caption}",e).repl("{width}",i).repl("{indicator}",r.indicatorNew).repl("{indicatorTitle}",r.indicatorNewTitle)):a=l.repl("{actions}","").repl("{caption}",e).repl("{width}",i).repl("{indicator}","").repl("{indicatorTitle}",""),a=H(a,n.previewThumbTags)},renderFileActions:function(e,i,t,a,n){if(!e&&!i)return"";var r=this,l=a===!1?"":' data-url="'+a+'"',o=n===!1?"":' data-key="'+n+'"',s=r.getLayoutTemplate("actionDelete"),d="",c=r.getLayoutTemplate("actions"),p=r.otherActionButtons.repl("{dataKey}",o),u=r.fileActionSettings,f=t?u.removeClass+" disabled":u.removeClass;return s=s.repl("{removeClass}",f).repl("{removeIcon}",u.removeIcon).repl("{removeTitle}",u.removeTitle).repl("{dataUrl}",l).repl("{dataKey}",o),e&&(d=r.getLayoutTemplate("actionUpload").repl("{uploadClass}",u.uploadClass).repl("{uploadIcon}",u.uploadIcon).repl("{uploadTitle}",u.uploadTitle)),c.repl("{delete}",s).repl("{upload}",d).repl("{other}",p)},setThumbStatus:function(e,i){var t=this,a="indicator"+i,n=a+"Title",r="file-preview-"+i.toLowerCase(),l=e.find(".file-upload-indicator"),o=t.fileActionSettings;e.removeClass("file-preview-success file-preview-error file-preview-loading"),l.html(o[a]),l.attr("title",o[n]),e.addClass(r)},clearPreview:function(){var e=this,i=e.$preview.find(e.showUploadedThumbs?".file-preview-frame:not(.file-preview-success)":".file-preview-frame");i.remove(),e.$preview.find(".file-preview-frame").length&&e.showPreview||e.resetUpload()},initPreview:function(e){var i,a=this,n=a.initialCaption||"";return t.count(a.id)?(i=t.out(a.id),n=e&&a.initialCaption?a.initialCaption:i.caption,a.$preview.html(i.content),a.setCaption(n),void(R(i.content)||a.$container.removeClass("file-input-new"))):(a.clearPreview(),void(e?a.setCaption(n):a.initCaption()))},initPreviewDeletes:function(){var i=this,a=i.deleteExtraData||{},n=function(){0===i.$preview.find(".kv-file-remove").length&&(i.reset(),i.initialCaption="")};i.$preview.find(".kv-file-remove").each(function(){var r=e(this),l=r.data("url")||i.deleteUrl,s=r.data("key");if(!R(l)&&void 0!==s){var d,c,p,u,f=r.closest(".file-preview-frame"),v=t.data[i.id],h=f.data("fileindex");h=parseInt(h.replace("init_","")),p=R(v.config)&&R(v.config[h])?null:v.config[h],u=R(p)||R(p.extra)?a:p.extra,"function"==typeof u&&(u=u()),c={id:r.attr("id"),key:s,extra:u},d=e.extend({url:l,type:"DELETE",dataType:"json",data:e.extend({key:s},u),beforeSend:function(e){i.ajaxAborted=!1,i.raise("filepredelete",[s,e,u]),i.ajaxAborted?e.abort():(o(f,"file-uploading"),o(r,"disabled"))},success:function(e,a,l){var o,d;return R(e)||R(e.error)?(t.unset(i.id,h),o=t.count(i.id),d=o>0?i.getMsgSelected(o):"",i.raise("filedeleted",[s,l,u]),i.setCaption(d),f.removeClass("file-uploading").addClass("file-deleted"),void f.fadeOut("slow",function(){i.clearObjects(f),f.remove(),n(),o||0!==i.getFileStack().length||(i.setCaption(""),i.reset())})):(c.jqXHR=l,c.response=e,i.showError(e.error,c,"filedeleteerror"),f.removeClass("file-uploading"),r.removeClass("disabled"),void n())},error:function(e,t,a){var r=i.parseError(e,a);c.jqXHR=e,c.response={},i.showError(r,c,"filedeleteerror"),f.removeClass("file-uploading"),n()}},i.ajaxDeleteSettings),r.off("click").on("click",function(){e.ajax(d)})}})},clearObjects:function(i){i.find("video audio").each(function(){this.pause(),e(this).remove()}),i.find("img object div").each(function(){e(this).remove()})},clearFileInput:function(){var i,t,a,n=this,r=n.$element;R(r.val())||(n.isIE9||n.isIE10?(i=r.closest("form"),t=e(document.createElement("form")),a=e(document.createElement("div")),r.before(a),i.length?i.after(t):a.after(t),t.append(r).trigger("reset"),a.before(r).remove(),t.remove()):r.val(""),n.fileInputCleared=!0)},resetUpload:function(){var e=this;e.uploadCache={content:[],config:[],tags:[],append:!0},e.uploadCount=0,e.uploadPercent=0,e.$btnUpload.removeAttr("disabled"),e.setProgress(0),o(e.$progress,"hide"),e.resetErrors(!1),e.ajaxAborted=!1,e.ajaxRequests=[]},cancel:function(){var i,t=this,a=t.ajaxRequests,n=a.length;if(n>0)for(i=0;n>i;i+=1)a[i].abort();t.getThumbs().each(function(){var i=e(this),a=i.attr("data-fileindex");i.removeClass("file-uploading"),void 0!==t.filestack[a]&&(i.find(".kv-file-upload").removeClass("disabled").removeAttr("disabled"),i.find(".kv-file-remove").removeClass("disabled").removeAttr("disabled")),t.unlock()})},cleanMemory:function(e){var i=e.is("img")?e.attr("src"):e.find("source").attr("src");W.revokeObjectURL(i)},hasInitialPreview:function(){var e=this;return!e.overwriteInitial&&t.count(e.id)},clear:function(){var i,t=this;t.$btnUpload.removeAttr("disabled"),t.getThumbs().find("video,audio,img").each(function(){t.cleanMemory(e(this))}),t.resetUpload(),t.filestack=[],t.clearFileInput(),t.resetErrors(!0),t.raise("fileclear"),t.hasInitialPreview()?(t.showFileIcon(),t.resetPreview(),t.setEllipsis(),t.initPreviewDeletes(),t.$container.removeClass("file-input-new")):(t.getThumbs().each(function(){t.clearObjects(e(this))}),t.$preview.html(""),i=!t.overwriteInitial&&t.initialCaption.length>0?t.initialCaption:"",t.setCaption(i),t.setEllipsis(),t.$caption.attr("title",""),o(t.$container,"file-input-new")),0===t.$container.find(".file-preview-frame").length&&(t.initCaption()||t.$captionContainer.find(".kv-caption-icon").hide(),t.setEllipsis()),t.hideFileIcon(),t.raise("filecleared"),t.$captionContainer.focus(),t.setFileDropZoneTitle()},resetPreview:function(){var e,i=this;t.count(i.id)?(e=t.out(i.id),i.$preview.html(e.content),i.setCaption(e.caption)):(i.clearPreview(),i.initCaption())},reset:function(){var e=this;e.resetPreview(),e.setEllipsis(),e.$container.find(".fileinput-filename").text(""),e.raise("filereset"),e.initialPreview.length>0&&e.$container.removeClass("file-input-new"),e.setFileDropZoneTitle(),e.filestack=[],e.formdata={}},disable:function(){var e=this;e.isDisabled=!0,e.raise("filedisabled"),e.$element.attr("disabled","disabled"),e.$container.find(".kv-fileinput-caption").addClass("file-caption-disabled"),e.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload").attr("disabled",!0),e.initDragDrop()},enable:function(){var e=this;e.isDisabled=!1,e.raise("fileenabled"),e.$element.removeAttr("disabled"),e.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled"),e.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload").removeAttr("disabled"),e.initDragDrop()},getThumbs:function(e){return e=e||"",this.$preview.find(".file-preview-frame:not(.file-preview-initial)"+e)},getExtraData:function(){var e=this,i=e.uploadExtraData;return"function"==typeof e.uploadExtraData&&(i=e.uploadExtraData()),i},uploadExtra:function(){var i=this,t=i.getExtraData();0!==t.length&&e.each(t,function(e,t){i.formdata.append(e,t)})},initXhr:function(e,i){var t=this;return e.upload&&e.upload.addEventListener("progress",function(e){var a=0,n=e.loaded||e.position,r=e.total;e.lengthComputable&&(a=Math.ceil(n/r*i)),t.uploadPercent=Math.max(a,t.uploadPercent),t.setProgress(t.uploadPercent)},!1),e},ajaxSubmit:function(i,t,a,n){var r,l=this;l.uploadExtra(),r=e.extend({xhr:function(){var i=e.ajaxSettings.xhr();return l.initXhr(i,98)},url:l.uploadUrl,type:"POST",dataType:"json",data:l.formdata,cache:!1,processData:!1,contentType:!1,beforeSend:i,success:t,complete:a,error:n},l.ajaxSettings),l.ajaxRequests.push(e.ajax(r))},initUploadSuccess:function(i,a,n){var r,l,o,s,d,c,p,u=this;"object"!=typeof i||e.isEmptyObject(i)||void 0!==i.initialPreview&&i.initialPreview.length>0&&(u.hasInitData=!0,d=i.initialPreview||[],c=i.initialPreviewConfig||[],p=i.initialPreviewThumbTags||[],r=void 0===i.append||i.append?!0:!1,u.overwriteInitial=!1,void 0===a||n?n?(u.uploadCache.content.push(d[0]),u.uploadCache.config.push(c[0]),u.uploadCache.tags.push(p[0]),u.uploadCache.append=r):(t.set(u.id,d,c,p,r),u.initPreview(),u.initPreviewDeletes()):(o=t.add(u.id,d,c[0],p[0],r),l=t.get(u.id,o,!1),s=e(l).hide(),a.after(s).fadeOut("slow",function(){s.fadeIn("slow").css("display:inline-block"),u.initPreviewDeletes(),u.clearFileInput(),a.remove()})))},initSuccessThumbs:function(){var i=this;i.getThumbs(".file-preview-success").each(function(){var t=e(this),a=t.find(".kv-file-remove");a.removeAttr("disabled").off("click").on("click",function(){var e=i.raise("filesuccessremove",[t.attr("id"),t.data("fileindex")]);i.cleanMemory(t),e!==!1&&t.fadeOut("slow",function(){t.remove(),i.$preview.find(".file-preview-frame").length||i.reset()})})})},uploadSingle:function(i,a,n){var r,l,s,d,c,p,u,f,v,h=this,m=h.getFileStack().length,g=new FormData,w=h.previewInitId+"-"+i,b=e("#"+w+":not(.file-preview-initial)"),x=b.find(".kv-file-upload"),C=b.find(".kv-file-remove"),y=h.filestack.length>0||!e.isEmptyObject(h.uploadExtraData),T={id:w,index:i};h.formdata=g,0===m||!y||x.hasClass("disabled")||h.abort(T)||(s=function(){var e=h.getThumbs(".file-uploading");e.length>0||h.fileBatchCompleted||(h.fileBatchCompleted=!0,setTimeout(function(){t.set(h.id,h.uploadCache.content,h.uploadCache.config,h.uploadCache.tags,h.uploadCache.append),h.hasInitData&&(h.initPreview(),h.initPreviewDeletes()),h.setProgress(100),h.unlock(),h.clearFileInput(),h.raise("filebatchuploadcomplete",[h.filestack,h.getExtraData()])},100))},d=function(){!n||0===m||h.uploadPercent>=100||(h.uploadCount+=1,l=80+Math.ceil(20*h.uploadCount/m),h.uploadPercent=Math.max(l,h.uploadPercent),h.setProgress(h.uploadPercent),h.initPreviewDeletes())},c=function(){x.removeAttr("disabled"),C.removeAttr("disabled"),b.removeClass("file-uploading")},p=function(t){r=h.getOutData(t),b.hasClass("file-preview-success")||(h.setThumbStatus(b,"Loading"),o(b,"file-uploading")),x.attr("disabled",!0),C.attr("disabled",!0),n||h.lock(),h.raise("filepreupload",[r,w,i]),T=e.extend(T,r),h.abort(T)&&(t.abort(),h.setProgress(100))},u=function(t,a,l){r=h.getOutData(l,t),T=e.extend(T,r),setTimeout(function(){R(t)||R(t.error)?(h.setThumbStatus(b,"Success"),x.hide(),h.filestack[i]=void 0,h.raise("fileuploaded",[r,w,i]),h.initUploadSuccess(t,b,n),n||h.resetFileStack()):(h.setThumbStatus(b,"Error"),h.showUploadError(t.error,T))},100)},f=function(){setTimeout(function(){d(),c(),n?s():h.unlock(!1),h.initSuccessThumbs()},100)},v=function(t,r,l){var o=h.parseError(t,l,n?a[i].name:null);h.setThumbStatus(b,"Error"),T=e.extend(T,h.getOutData(t)),h.showUploadError(o,T)},g.append(h.uploadFileAttr,a[i]),g.append("file_id",i),h.ajaxSubmit(p,u,f,v))},uploadBatch:function(){var i,t,a,n,r,l=this,s=l.filestack,d=s.length,c=l.filestack.length>0||!e.isEmptyObject(l.uploadExtraData),p={};l.formdata=new FormData,0!==d&&c&&!l.abort(p)&&(i=function(){e.each(s,function(e){l.filestack[e]=void 0}),l.clearFileInput()},t=function(i){l.lock();var t=l.getOutData(i);l.showPreview&&l.getThumbs().each(function(){var i=e(this),t=i.find(".kv-file-upload"),a=i.find(".kv-file-remove");i.hasClass("file-preview-success")||(l.setThumbStatus(i,"Loading"),o(i,"file-uploading")),t.attr("disabled",!0),a.attr("disabled",!0)}),l.raise("filebatchpreupload",[t]),l.abort(t)&&i.abort()},a=function(t,a,n){var r=l.getOutData(n,t),o=l.getThumbs(),s=R(t.errorkeys)?[]:t.errorkeys;R(t)||R(t.error)?(l.raise("filebatchuploadsuccess",[r]),i(),l.showPreview?(o.each(function(){var i=e(this),t=i.find(".kv-file-upload");i.find(".kv-file-upload").hide(),l.setThumbStatus(i,"Success"),i.removeClass("file-uploading"),t.removeAttr("disabled")}),l.initUploadSuccess(t)):l.reset()):(l.showPreview&&(o.each(function(){var i=e(this),t=i.find(".kv-file-remove"),a=i.find(".kv-file-upload");return i.removeClass("file-uploading"),a.removeAttr("disabled"),t.removeAttr("disabled"),0===s.length?void l.setThumbStatus(i,"Error"):void(-1!==e.inArray(key,s)?l.setThumbStatus(i,"Error"):(i.find(".kv-file-upload").hide(),l.setThumbStatus(i,"Success"),l.filestack[key]=void 0)); + }),l.initUploadSuccess(t)),l.showUploadError(t.error,r,"filebatchuploaderror"))},n=function(){l.setProgress(100),l.unlock(),l.initSuccessThumbs(),l.raise("filebatchuploadcomplete",[l.filestack,l.getExtraData()]),l.clearFileInput()},r=function(i,t,a){var n=l.getOutData(i),r=l.parseError(i,a);l.showUploadError(r,n,"filebatchuploaderror"),l.uploadFileCount=d-1,l.showPreview&&(l.getThumbs().each(function(){var i=e(this),t=i.attr("data-fileindex");i.removeClass("file-uploading"),void 0!==l.filestack[t]&&l.setThumbStatus(i,"Error")}),l.getThumbs().removeClass("file-uploading"),l.getThumbs(" .kv-file-upload").removeAttr("disabled"),l.getThumbs(" .kv-file-delete").removeAttr("disabled"))},e.each(s,function(e,i){R(s[e])||l.formdata.append(l.uploadFileAttr,i)}),l.ajaxSubmit(t,a,n,r))},uploadExtraOnly:function(){var e,i,t,a,n=this,r={};n.formdata=new FormData,n.abort(r)||(e=function(e){n.lock();var i=n.getOutData(e);n.raise("filebatchpreupload",[i]),n.setProgress(50),r.data=i,r.xhr=e,n.abort(r)&&(e.abort(),n.setProgress(100))},i=function(e,i,t){var a=n.getOutData(t,e);R(e)||R(e.error)?(n.raise("filebatchuploadsuccess",[a]),n.clearFileInput(),n.initUploadSuccess(e)):n.showUploadError(e.error,a,"filebatchuploaderror")},t=function(){n.setProgress(100),n.unlock(),n.raise("filebatchuploadcomplete",[n.filestack,n.getExtraData()]),n.clearFileInput()},a=function(e,i,t){var a=n.getOutData(e),l=n.parseError(e,t);r.data=a,n.showUploadError(l,a,"filebatchuploaderror")},n.ajaxSubmit(e,i,t,a))},hideFileIcon:function(){this.overwriteInitial&&this.$captionContainer.find(".kv-caption-icon").hide()},showFileIcon:function(){this.$captionContainer.find(".kv-caption-icon").show()},resetErrors:function(e){var i=this,t=i.$errorContainer;i.isError=!1,i.$container.removeClass("has-error"),t.html(""),e?t.fadeOut("slow"):t.hide()},showFolderError:function(e){var i=this,t=i.$errorContainer;e&&(t.html(i.msgFoldersNotAllowed.repl("{n}",e)),t.fadeIn(800),o(i.$container,"has-error"),i.raise("filefoldererror",[e]))},showUploadError:function(e,i,t){var a=this,n=a.$errorContainer,r=t||"fileuploaderror";return 0===n.find("ul").length?n.html("
  • "+e+"
"):n.find("ul").append("
  • "+e+"
  • "),n.fadeIn(800),a.raise(r,[i]),o(a.$container,"has-error"),!0},showError:function(e,i,t){var a=this,n=a.$errorContainer,r=t||"fileerror";return i=i||{},i.reader=a.reader,n.html(e),n.fadeIn(800),a.raise(r,[i]),a.isUploadable||a.clearFileInput(),o(a.$container,"has-error"),a.$btnUpload.attr("disabled",!0),!0},errorHandler:function(e,i){var t=this,a=e.target.error;switch(a.code){case a.NOT_FOUND_ERR:t.showError(t.msgFileNotFound.replace("{name}",i));break;case a.SECURITY_ERR:t.showError(t.msgFileSecured.replace("{name}",i));break;case a.NOT_READABLE_ERR:t.showError(t.msgFileNotReadable.replace("{name}",i));break;case a.ABORT_ERR:t.showError(t.msgFilePreviewAborted.replace("{name}",i));break;default:t.showError(t.msgFilePreviewError.replace("{name}",i))}},parseFileType:function(e){var i,t,a,n,r=this;for(n=0;n=0,b=R(f)||!R(f)&&-1!==f.indexOf(i.type),x=d.renderFileFooter(p,h.width),C="",y=a.slice(a.lastIndexOf("-")+1);w&&b?("text"===c?(l=Z(t.target.result),l.length>m&&(o="text-"+B(),s=.75*window.innerHeight,C=d.getLayoutTemplate("modal").repl("{id}",o).repl("{title}",p).repl("{height}",s).repl("{body}",l),g=g.repl("{title}",p).repl("{dialog}","$('#"+o+"').modal('show')"),l=l.substring(0,m-1)+g),r=v.repl("{previewId}",a).repl("{caption}",p).repl("{frameClass}","").repl("{type}",i.type).repl("{width}",h.width).repl("{height}",h.height).repl("{data}",l).repl("{footer}",x).repl("{fileindex}",y)+C):r=v.repl("{previewId}",a).repl("{caption}",p).repl("{frameClass}","").repl("{type}",i.type).repl("{data}",n).repl("{width}",h.width).repl("{height}",h.height).repl("{footer}",x).repl("{fileindex}",y),d.$preview.append("\n"+r),d.validateImage(e,a)):d.previewDefault(i,a)}},slugDefault:function(e){return R(e)?"":e.split(/(\\|\/)/g).pop().replace(/[^\w\u00C0-\u017F\-.\\\/ ]+/g,"")},getFileStack:function(e){var i=this;return i.filestack.filter(function(i){return e?void 0!==i:void 0!==i&&null!==i})},readFiles:function(i){function t(e){if(R(n.attr("multiple"))&&(u=1),e>=u)return a.isUploadable&&a.filestack.length>0?a.raise("filebatchselected",[a.getFileStack()]):a.raise("filebatchselected",[i]),o.removeClass("loading"),void s.html("");var m,g,w,b,x,C,y=v+e,T=p+"-"+y,E=i[e],k=a.slug(E.name),F=(E.size||0)/1e3,$="",I=W.createObjectURL(E),D=0,P=a.allowedFileTypes,S=R(P)?"":P.join(", "),U=a.allowedFileExtensions,j=R(U)?"":U.join(", ");if(R(U)||($=new RegExp("\\.("+U.join("|")+")$","i")),F=F.toFixed(2),a.maxFileSize>0&&F>a.maxFileSize)return b=a.msgSizeTooLarge.replace("{name}",k).replace("{size}",F).replace("{maxSize}",a.maxFileSize),void(a.isError=h(b,E,T,e));if(!R(P)&&z(P)){for(w=0;w0&&void 0!==FileReader?(s.html(d.replace("{index}",e+1).replace("{files}",u)),o.addClass("loading"),l.onerror=function(e){a.errorHandler(e,k)},l.onload=function(i){a.previewFile(e,E,i,T,I),a.initFileActions()},l.onloadend=function(){b=c.replace("{index}",e+1).replace("{files}",u).replace("{percent}",50).replace("{name}",k),setTimeout(function(){s.html(b),t(e+1),a.updateFileDetails(u)},100),a.raise("fileloaded",[E,T,e,l])},l.onprogress=function(i){if(i.lengthComputable){var t=i.loaded/i.total*100,a=Math.ceil(t);b=c.replace("{index}",e+1).replace("{files}",u).replace("{percent}",a).replace("{name}",k),setTimeout(function(){s.html(b)},100)}},m=M("text",f)?f.text:O.text,m(E.type,k)?l.readAsText(E,a.textEncoding):l.readAsArrayBuffer(E)):(a.previewDefault(E,T),setTimeout(function(){t(e+1),a.updateFileDetails(u)},100),a.raise("fileloaded",[E,T,e,l])),void a.filestack.push(E)):(a.filestack.push(E),setTimeout(t(e+1),100),void a.raise("fileloaded",[E,T,e,l])):(b=a.msgInvalidFileExtension.replace("{name}",k).replace("{extensions}",j),void(a.isError=h(b,E,T,e)))}this.reader=new FileReader;var a=this,n=a.$element,r=a.$preview,l=a.reader,o=a.$previewContainer,s=a.$previewStatus,d=a.msgLoading,c=a.msgProgress,p=a.previewInitId,u=i.length,f=a.fileTypeSettings,v=a.filestack.length,h=function(t,n,r,l){var o=e.extend(a.getOutData({},{},i),{id:r,index:l}),s={id:r,index:l,file:n,files:i};return a.previewDefault(n,r,!0),a.isUploadable?a.showUploadError(t,o):a.showError(t,s)};t(0),a.updateFileDetails(u,!1)},updateFileDetails:function(e){var i=this,a=i.$element,n=i.getFileStack(),r=a.val()||n.length&&n[0].name||"",l=i.slug(r),o=i.isUploadable?n.length:e,s=t.count(i.id)+o,d=o>1?i.getMsgSelected(s):l;i.isError?(i.$previewContainer.removeClass("loading"),i.$previewStatus.html(""),i.$captionContainer.find(".kv-caption-icon").hide()):i.showFileIcon(),i.setCaption(d,i.isError),i.$container.removeClass("file-input-new file-input-ajax-new"),1===arguments.length&&i.raise("fileselect",[e,l]),t.count(i.id)&&i.initPreviewDeletes()},change:function(i){var a=this,n=a.$element;if(!a.isUploadable&&R(n.val())&&a.fileInputCleared)return void(a.fileInputCleared=!1);a.fileInputCleared=!1;var r,l,o,s,d=a.$preview,c=arguments.length>1,p=c?i.originalEvent.dataTransfer.files:n.get(0).files,u=R(n.attr("multiple")),f=0,v=0,h=a.filestack.length,m=a.isUploadable,g=function(i,t,n,r){var l=e.extend(a.getOutData({},{},p),{id:n,index:r}),o={id:n,index:r,file:t,files:p};return a.isUploadable?a.showUploadError(i,l):a.showError(i,o)};if(a.reader=null,a.resetUpload(),a.hideFileIcon(),a.isUploadable&&a.$container.find(".file-drop-zone ."+a.dropZoneTitleClass).remove(),c)for(r=[];p[f];)s=p[f],s.type||s.size%4096!==0?r.push(s):v++,f++;else r=void 0===i.target.files?i.target&&i.target.value?[{name:i.target.value.replace(/^.+\\/,"")}]:[]:i.target.files;if(R(r)||0===r.length)return m||a.clear(),a.showFolderError(v),void a.raise("fileselectnone");if(a.resetErrors(),o=a.isUploadable?a.getFileStack().length+r.length:r.length,a.maxFileCount>0&&o>a.maxFileCount)return l=a.msgFilesTooMany.replace("{m}",a.maxFileCount).replace("{n}",o),a.isError=g(l,null,null,null),a.$captionContainer.find(".kv-caption-icon").hide(),a.setCaption("",!0),a.setEllipsis(),void a.$container.removeClass("file-input-new file-input-ajax-new");if(!m||u&&h>0){if(a.hasInitialPreview()){var w=t.out(a.id);d.html(w.content),a.setCaption(w.caption),a.initPreviewDeletes()}else a.clearPreview();u&&h>0&&(a.filestack=[])}else!m||0!==h||t.count(a.id)&&!a.overwriteInitial||(a.clearPreview(),a.filestack=[]);a.isPreviewable?a.readFiles(r):a.updateFileDetails(1),a.showFolderError(v)},validateImage:function(e,i){var t,a,n,r,l=this,o=l.$preview,s=o.find("#"+i),d="Untitled",c=s.find("img");c.length&&c.on("load",function(){a=s.width(),n=o.width(),a>n&&(c.css("width","100%"),s.css("width","97%")),r=c.closest(".file-preview-frame").find(".file-caption-name"),r.length&&(r.width(c.width()),d=r.text(),r.attr("title",d)),t={ind:e,id:i},l.checkDimensions(e,"Small",c,s,d,"Width",t),l.checkDimensions(e,"Small",c,s,d,"Height",t),l.checkDimensions(e,"Large",c,s,d,"Width",t),l.checkDimensions(e,"Large",c,s,d,"Height",t),l.raise("fileimageloaded",[i]),W.revokeObjectURL(c.attr("src"))})},checkDimensions:function(e,i,t,a,n,r,l){var o,s,d,c,p=this,u="Small"===i?"min":"max",f=p[u+"Image"+r];!R(f)&&t.length&&(d=t[0],s="Width"===r?d.naturalWidth||d.width:d.naturalHeight||d.height,c="Small"===i?s>=f:f>=s,c||(o=p["msgImage"+r+i].replace("{name}",n).replace("{size}",f),p.showUploadError(o,l),p.setThumbStatus(a,"Error"),p.filestack[e]=null))},initCaption:function(){var e=this,i=e.initialCaption||"";return e.overwriteInitial||R(i)?(e.$caption.html(""),!1):(e.setCaption(i),!0)},setCaption:function(i,t){var a,n,r=this;if(t)a=e("
    "+r.msgValidationError+"
    ").text(),n=''+r.msgValidationErrorIcon+a+"";else{if(R(i)||0===r.$caption.length)return;a=e("
    "+i+"
    ").text(),n=r.getLayoutTemplate("icon")+a}r.$caption.html(n),r.$caption.attr("title",a),r.$captionContainer.find(".file-caption-ellipsis").attr("title",a),r.setEllipsis()},initBrowse:function(e){var i=this;i.$btnFile=e.find(".btn-file"),i.$btnFile.append(i.$element)},createContainer:function(){var i=this,t=e(document.createElement("span")).attr({"class":"file-input file-input-new"}).html(i.renderMain());return i.$element.before(t),i.initBrowse(t),t},refreshContainer:function(){var e=this,i=e.$container;i.before(e.$element),i.html(e.renderMain()),e.initBrowse(i)},renderMain:function(){var e=this,i=e.isUploadable&&e.dropZoneEnabled?" file-drop-zone":"",t=e.showPreview?e.getLayoutTemplate("preview").repl("{class}",e.previewClass).repl("{dropClass}",i):"",a=e.isDisabled?e.captionClass+" file-caption-disabled":e.captionClass,n=e.captionTemplate.repl("{class}",a+" kv-fileinput-caption");return e.mainTemplate.repl("{class}",e.mainClass).repl("{preview}",t).repl("{caption}",n).repl("{upload}",e.renderUpload()).repl("{remove}",e.renderRemove()).repl("{cancel}",e.renderCancel()).repl("{browse}",e.renderBrowse())},renderBrowse:function(){var e=this,i=e.browseClass+" btn-file",t="";return e.isDisabled&&(t=" disabled "),'
    "+e.browseIcon+e.browseLabel+"
    "},renderRemove:function(){var e=this,i=e.removeClass+" fileinput-remove fileinput-remove-button",t="";return e.showRemove?(e.isDisabled&&(t=" disabled "),'"):""},renderCancel:function(){var e=this,i=e.cancelClass+" fileinput-cancel fileinput-cancel-button";return e.showCancel?'":""},renderUpload:function(){var e=this,i=e.uploadClass+" kv-fileinput-upload fileinput-upload-button",t="",a="";return e.showUpload?(e.isDisabled&&(a=" disabled "),t=!e.isUploadable||e.isDisabled?'":'"+e.uploadIcon+e.uploadLabel+""):""}},e.fn.fileinput=function(t){if(n()||i(9)){var a=Array.apply(null,arguments);return a.shift(),this.each(function(){var i,n=e(this),r=n.data("fileinput"),l="object"==typeof t&&t,o=l.language||n.data("language")||"en";r||(i=e.extend({},e.fn.fileinput.defaults),"en"===o||R(e.fn.fileinputLocales[o])||(i=e.extend(i,e.fn.fileinputLocales[o])),r=new _(this,e.extend(i,l,n.data())),n.data("fileinput",r)),"string"==typeof t&&r[t].apply(r,a)})}},e.fn.fileinput.defaults={language:"en",showCaption:!0,showPreview:!0,showRemove:!0,showUpload:!0,showCancel:!0,showUploadedThumbs:!0,mainClass:"",previewClass:"",captionClass:"",mainTemplate:null,initialCaption:"",initialPreview:[],initialPreviewDelimiter:"*$$*",initialPreviewConfig:[],initialPreviewThumbTags:[],previewThumbTags:{},initialPreviewShowDelete:!0,deleteUrl:"",deleteExtraData:{},overwriteInitial:!0,layoutTemplates:U,previewTemplates:j,allowedPreviewTypes:A,allowedPreviewMimeTypes:null,allowedFileTypes:null,allowedFileExtensions:null,customLayoutTags:{},customPreviewTags:{},previewSettings:L,fileTypeSettings:O,previewFileIcon:'',browseIcon:'  ',browseClass:"btn btn-primary",removeIcon:' ',removeClass:"btn btn-default",cancelIcon:' ',cancelClass:"btn btn-default",uploadIcon:' ',uploadClass:"btn btn-default",uploadUrl:null,uploadAsync:!0,uploadExtraData:{},minImageWidth:null,minImageHeight:null,maxImageWidth:null,maxImageHeight:null,maxFileSize:0,minFileCount:0,maxFileCount:0,msgValidationErrorClass:"text-danger",msgValidationErrorIcon:' ',msgErrorClass:"file-error-message",progressClass:"progress-bar progress-bar-success progress-bar-striped active",progressCompleteClass:"progress-bar progress-bar-success",previewFileType:"image",wrapTextLength:250,wrapIndicator:' […]',elCaptionContainer:null,elCaptionText:null,elPreviewContainer:null,elPreviewImage:null,elPreviewStatus:null,elErrorContainer:null,slugCallback:null,dropZoneEnabled:!0,dropZoneTitleClass:"file-drop-zone-title",fileActionSettings:{},otherActionButtons:"",textEncoding:"UTF-8",ajaxSettings:{},ajaxDeleteSettings:{},showAjaxErrorDetails:!0},e.fn.fileinputLocales.en={fileSingle:"file",filePlural:"files",browseLabel:"Browse …",removeLabel:"Remove",removeTitle:"Clear selected files",cancelLabel:"Cancel",cancelTitle:"Abort ongoing upload",uploadLabel:"Upload",uploadTitle:"Upload selected files",msgSizeTooLarge:'File "{name}" ({size} KB) exceeds maximum allowed upload size of {maxSize} KB. Please retry your upload!',msgFilesTooLess:"You must select at least {n} {files} to upload. Please retry your upload!",msgFilesTooMany:"Number of files selected for upload ({n}) exceeds maximum allowed limit of {m}. Please retry your upload!",msgFileNotFound:'File "{name}" not found!',msgFileSecured:'Security restrictions prevent reading the file "{name}".',msgFileNotReadable:'File "{name}" is not readable.',msgFilePreviewAborted:'File preview aborted for "{name}".',msgFilePreviewError:'An error occurred while reading the file "{name}".',msgInvalidFileType:'Invalid type for file "{name}". Only "{types}" files are supported.',msgInvalidFileExtension:'Invalid extension for file "{name}". Only "{extensions}" files are supported.',msgValidationError:"File Upload Error",msgLoading:"Loading file {index} of {files} …",msgProgress:"Loading file {index} of {files} - {name} - {percent}% completed.",msgSelected:"{n} {files} selected",msgFoldersNotAllowed:"Drag & drop files only! {n} folder(s) dropped were skipped.",msgImageWidthSmall:'Width of image file "{name}" must be at least {size} px.',msgImageHeightSmall:'Height of image file "{name}" must be at least {size} px.',msgImageWidthLarge:'Width of image file "{name}" cannot exceed {size} px.',msgImageHeightLarge:'Height of image file "{name}" cannot exceed {size} px.',dropZoneTitle:"Drag & drop files here …"},e.extend(e.fn.fileinput.defaults,e.fn.fileinputLocales.en),e.fn.fileinput.Constructor=_,e(document).ready(function(){var i=e("input.file[type=file]");i.length&&i.fileinput()})}(window.jQuery); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput_locale_LANG.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput_locale_LANG.js index cff86334..492d8c4d 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput_locale_LANG.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput_locale_LANG.js @@ -1,45 +1,45 @@ -/*! - * FileInput <_LANG_> Translations - * - * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or - * any HTML markup tags in the messages must not be converted or translated. - * - * @see http://github.com/kartik-v/bootstrap-fileinput - * - * NOTE: this file must be saved in UTF-8 encoding. - */ -(function ($) { - "use strict"; - - $.fn.fileinputLocales['_LANG_'] = { - fileSingle: 'file', - filePlural: 'files', - browseLabel: 'Browse …', - removeLabel: 'Remove', - removeTitle: 'Clear selected files', - cancelLabel: 'Cancel', - cancelTitle: 'Abort ongoing upload', - uploadLabel: 'Upload', - uploadTitle: 'Upload selected files', - msgSizeTooLarge: 'File "{name}" ({size} KB) exceeds maximum allowed upload size of {maxSize} KB. Please retry your upload!', - msgFilesTooLess: 'You must select at least {n} {files} to upload. Please retry your upload!', - msgFilesTooMany: 'Number of files selected for upload ({n}) exceeds maximum allowed limit of {m}. Please retry your upload!', - msgFileNotFound: 'File "{name}" not found!', - msgFileSecured: 'Security restrictions prevent reading the file "{name}".', - msgFileNotReadable: 'File "{name}" is not readable.', - msgFilePreviewAborted: 'File preview aborted for "{name}".', - msgFilePreviewError: 'An error occurred while reading the file "{name}".', - msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.', - msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.', - msgValidationError: 'File Upload Error', - msgLoading: 'Loading file {index} of {files} …', - msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.', - msgSelected: '{n} {files} selected', - msgFoldersNotAllowed: 'Drag & drop files only! Skipped {n} dropped folder(s).', - msgImageWidthSmall: 'Width of image file "{name}" must be at least {size} px.', - msgImageHeightSmall: 'Height of image file "{name}" must be at least {size} px.', - msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.', - msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.', - dropZoneTitle: 'Drag & drop files here …' - }; +/*! + * FileInput <_LANG_> Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['_LANG_'] = { + fileSingle: 'file', + filePlural: 'files', + browseLabel: 'Browse …', + removeLabel: 'Remove', + removeTitle: 'Clear selected files', + cancelLabel: 'Cancel', + cancelTitle: 'Abort ongoing upload', + uploadLabel: 'Upload', + uploadTitle: 'Upload selected files', + msgSizeTooLarge: 'File "{name}" ({size} KB) exceeds maximum allowed upload size of {maxSize} KB. Please retry your upload!', + msgFilesTooLess: 'You must select at least {n} {files} to upload. Please retry your upload!', + msgFilesTooMany: 'Number of files selected for upload ({n}) exceeds maximum allowed limit of {m}. Please retry your upload!', + msgFileNotFound: 'File "{name}" not found!', + msgFileSecured: 'Security restrictions prevent reading the file "{name}".', + msgFileNotReadable: 'File "{name}" is not readable.', + msgFilePreviewAborted: 'File preview aborted for "{name}".', + msgFilePreviewError: 'An error occurred while reading the file "{name}".', + msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.', + msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.', + msgValidationError: 'File Upload Error', + msgLoading: 'Loading file {index} of {files} …', + msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.', + msgSelected: '{n} {files} selected', + msgFoldersNotAllowed: 'Drag & drop files only! Skipped {n} dropped folder(s).', + msgImageWidthSmall: 'Width of image file "{name}" must be at least {size} px.', + msgImageHeightSmall: 'Height of image file "{name}" must be at least {size} px.', + msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.', + msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.', + dropZoneTitle: 'Drag & drop files here …' + }; })(window.jQuery); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput_locale_zh.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput_locale_zh.js index 9092b750..12d83710 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput_locale_zh.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-fileinput/js/fileinput_locale_zh.js @@ -1,49 +1,49 @@ -/*! - * FileInput Chinese Translations - * - * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or - * any HTML markup tags in the messages must not be converted or translated. - * - * @see http://github.com/kartik-v/bootstrap-fileinput - * @author kangqf - * - * NOTE: this file must be saved in UTF-8 encoding. - */ -(function ($) { - "use strict"; - - $.fn.fileinputLocales['zh'] = { - fileSingle: '文件', - filePlural: '多个文件', - browseLabel: '选择 …', - removeLabel: '移除', - removeTitle: '清除选中文件', - cancelLabel: 'å–消', - cancelTitle: 'å–消进行中的上传', - uploadLabel: '上传', - uploadTitle: '上传选中文件', - msgSizeTooLarge: '文件 "{name}" ({size} KB) 超过了å…è®¸å¤§å° {maxSize} KB. 请é‡æ–°ä¸Šä¼ !', - msgFilesTooLess: '你必须选择最少 {n} {files} æ¥ä¸Šä¼ . 请é‡æ–°ä¸Šä¼ !', - msgFilesTooMany: '选择的上传文件个数 ({n}) 超出最大文件的é™åˆ¶ä¸ªæ•° {m}. 请é‡æ–°ä¸Šä¼ !', - msgFileNotFound: '文件 "{name}" 未找到!', - msgFileSecured: '安全é™åˆ¶ï¼Œä¸ºäº†é˜²æ­¢è¯»å–文件 "{name}".', - msgFileNotReadable: '文件 "{name}" ä¸å¯è¯».', - msgFilePreviewAborted: 'å–消 "{name}" 的预览.', - msgFilePreviewError: 'è¯»å– "{name}" 时出现了一个错误.', - msgInvalidFileType: 'ä¸æ­£ç¡®çš„类型 "{name}". åªæ”¯æŒ "{types}" 类型的文件.', - msgInvalidFileExtension: 'ä¸æ­£ç¡®çš„文件扩展å "{name}". åªæ”¯æŒ "{extensions}" 的文件扩展å.', - msgValidationError: '文件上传错误', - msgLoading: '加载第 {index} 文件 å…± {files} …', - msgProgress: '加载第 {index} 文件 å…± {files} - {name} - {percent}% 完æˆ.', - msgSelected: '{n} {files} 选中', - msgFoldersNotAllowed: 'åªæ”¯æŒæ‹–拽文件! 跳过 {n} 拖拽的文件夹.', - msgImageWidthSmall: '宽度的图åƒæ–‡ä»¶çš„"{name}"的必须是至少{size}åƒç´ .', - msgImageHeightSmall: '图åƒæ–‡ä»¶çš„"{name}"的高度必须至少为{size}åƒç´ .', - msgImageWidthLarge: '宽度的图åƒæ–‡ä»¶"{name}"ä¸èƒ½è¶…过{size}åƒç´ .', - msgImageHeightLarge: '图åƒæ–‡ä»¶"{name}"的高度ä¸èƒ½è¶…过{size}åƒç´ .', - dropZoneTitle: '拖拽文件到这里 …', - slugCallback: function(text) { - return text ? text.split(/(\\|\/)/g).pop().replace(/[^\w\u4e00-\u9fa5\-.\\\/ ]+/g, '') : ''; - } - }; +/*! + * FileInput Chinese Translations + * + * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or + * any HTML markup tags in the messages must not be converted or translated. + * + * @see http://github.com/kartik-v/bootstrap-fileinput + * @author kangqf + * + * NOTE: this file must be saved in UTF-8 encoding. + */ +(function ($) { + "use strict"; + + $.fn.fileinputLocales['zh'] = { + fileSingle: '文件', + filePlural: '多个文件', + browseLabel: '选择 …', + removeLabel: '移除', + removeTitle: '清除选中文件', + cancelLabel: 'å–消', + cancelTitle: 'å–消进行中的上传', + uploadLabel: '上传', + uploadTitle: '上传选中文件', + msgSizeTooLarge: '文件 "{name}" ({size} KB) 超过了å…è®¸å¤§å° {maxSize} KB. 请é‡æ–°ä¸Šä¼ !', + msgFilesTooLess: '你必须选择最少 {n} {files} æ¥ä¸Šä¼ . 请é‡æ–°ä¸Šä¼ !', + msgFilesTooMany: '选择的上传文件个数 ({n}) 超出最大文件的é™åˆ¶ä¸ªæ•° {m}. 请é‡æ–°ä¸Šä¼ !', + msgFileNotFound: '文件 "{name}" 未找到!', + msgFileSecured: '安全é™åˆ¶ï¼Œä¸ºäº†é˜²æ­¢è¯»å–文件 "{name}".', + msgFileNotReadable: '文件 "{name}" ä¸å¯è¯».', + msgFilePreviewAborted: 'å–消 "{name}" 的预览.', + msgFilePreviewError: 'è¯»å– "{name}" 时出现了一个错误.', + msgInvalidFileType: 'ä¸æ­£ç¡®çš„类型 "{name}". åªæ”¯æŒ "{types}" 类型的文件.', + msgInvalidFileExtension: 'ä¸æ­£ç¡®çš„文件扩展å "{name}". åªæ”¯æŒ "{extensions}" 的文件扩展å.', + msgValidationError: '文件上传错误', + msgLoading: '加载第 {index} 文件 å…± {files} …', + msgProgress: '加载第 {index} 文件 å…± {files} - {name} - {percent}% 完æˆ.', + msgSelected: '{n} {files} 选中', + msgFoldersNotAllowed: 'åªæ”¯æŒæ‹–拽文件! 跳过 {n} 拖拽的文件夹.', + msgImageWidthSmall: '宽度的图åƒæ–‡ä»¶çš„"{name}"的必须是至少{size}åƒç´ .', + msgImageHeightSmall: '图åƒæ–‡ä»¶çš„"{name}"的高度必须至少为{size}åƒç´ .', + msgImageWidthLarge: '宽度的图åƒæ–‡ä»¶"{name}"ä¸èƒ½è¶…过{size}åƒç´ .', + msgImageHeightLarge: '图åƒæ–‡ä»¶"{name}"的高度ä¸èƒ½è¶…过{size}åƒç´ .', + dropZoneTitle: '拖拽文件到这里 …', + slugCallback: function(text) { + return text ? text.split(/(\\|\/)/g).pop().replace(/[^\w\u4e00-\u9fa5\-.\\\/ ]+/g, '') : ''; + } + }; })(window.jQuery); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-growl/bootstrap-growl.min.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-growl/bootstrap-growl.min.js index ce6deb10..40642941 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-growl/bootstrap-growl.min.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-growl/bootstrap-growl.min.js @@ -1,2 +1,2 @@ -/* Project: Bootstrap Growl - v2.0.0 | Author: Mouse0270 aka Robert McIntosh | License: MIT License | Website: https://github.com/mouse0270/bootstrap-growl */ +/* Project: Bootstrap Growl - v2.0.0 | Author: Mouse0270 aka Robert McIntosh | License: MIT License | Website: https://github.com/mouse0270/bootstrap-growl */ (function(e,t,n,r){var i="growl",s="plugin_"+i,o={element:"body",type:"info",allow_dismiss:true,placement:{from:"top",align:"right"},offset:20,spacing:10,z_index:1031,delay:5e3,timer:1e3,url_target:"_blank",mouse_over:false,animate:{enter:"animated fadeInDown",exit:"animated fadeOutUp"},icon_type:"class",template:''};var u=function(t,n){o=e.extend(true,{},o,n)},a=function(t,n,r){var n={content:{message:typeof n=="object"?n.message:n,title:n.title?n.title:null,icon:n.icon?n.icon:null,url:n.url?n.url:null}};r=e.extend(true,{},n,r);this.settings=e.extend(true,{},o,r);plugin=this;f(r,this.settings,plugin);this.$template=$template},f=function(t,n,r){var i={settings:n,$element:e(n.element),template:n.template};$template=l(i);c($template,i.settings);h($template,i.settings);p($template,i.settings,r)},l=function(t){var n=e(t.settings.template);n.addClass("alert-"+t.settings.type);n.attr("data-growl-position",t.settings.placement.from+"-"+t.settings.placement.align);n.find('[data-growl="dismiss"]').css("display","none");if(t.settings.allow_dismiss){n.find('[data-growl="dismiss"]').css("display","inline-block")}return n},c=function(e,t){e.find('[data-growl="dismiss"]').css({position:"absolute",top:"5px",right:"10px","z-index":t.z_index-1>=1?t.z_index-1:1});if(t.content.icon){if(t.icon_type.toLowerCase()=="class"){e.find('[data-growl="icon"]').addClass(t.content.icon)}else{if(e.find('[data-growl="icon"]').is("img")){e.find('[data-growl="icon"]').attr("src",t.content.icon)}else{e.find('[data-growl="icon"]').append('')}}}if(t.content.title){e.find('[data-growl="title"]').html(t.content.title)}if(t.content.message){e.find('[data-growl="message"]').html(t.content.message)}if(t.content.url){e.find('[data-growl="url"]').attr("href",t.content.url).attr("target",t.url_target);e.find('[data-growl="url"]').css({position:"absolute",top:"0px",left:"0px",width:"100%",height:"100%","z-index":t.z_index-2>=1?t.z_index-2:1})}},h=function(t,n){var r=n.offset,i={position:n.element==="body"?"fixed":"absolute",margin:0,"z-index":n.z_index,display:"inline-block"};e('[data-growl-position="'+n.placement.from+"-"+n.placement.align+'"]').each(function(){return r=Math.max(r,parseInt(e(this).css(n.placement.from))+e(this).outerHeight()+n.spacing)});i[n.placement.from]=r+"px";t.css(i);e(n.element).append(t);switch(n.placement.align){case"center":t.css({left:"50%",marginLeft:-(t.outerWidth()/2)+"px"});break;case"left":t.css("left",n.offset+"px");break;case"right":t.css("right",n.offset+"px");break}t.addClass("growl-animated")},p=function(e,t,n){e.addClass(t.animate.enter);e.find('[data-growl="dismiss"]').on("click",function(){n.close()});e.on("mouseover",function(t){e.addClass("hovering")}).on("mouseout",function(){e.removeClass("hovering")});if(t.delay>=1){e.data("growl-delay",t.delay);var r=setInterval(function(){var i=parseInt(e.data("growl-delay"))-t.timer;console.log();if(!e.hasClass("hovering")&&t.mouse_over=="pause"||t.mouse_over!="pause"){e.data("growl-delay",i)}if(i<=0){clearInterval(r);n.close()}},t.timer)}};a.prototype={update:function(e,t){switch(e){case"icon":if(this.settings.icon_type.toLowerCase()=="class"){this.$template.find('[data-growl="icon"]').removeClass(this.settings.content.icon);this.$template.find('[data-growl="icon"]').addClass(t)}else{if(this.$template.find('[data-growl="icon"]').is("img")){this.$template.find('[data-growl="icon"]')}else{this.$template.find('[data-growl="icon"]').find("img").attr().attr("src",t)}}break;case"url":this.$template.find('[data-growl="url"]').attr("href",t);break;case"type":this.$template.removeClass("alert-"+this.settings.type);this.$template.addClass("alert-"+t);break;default:this.$template.find('[data-growl="'+e+'"]').html(t)}return this},close:function(){var t=this.$template,n=this.settings,r=t.css(n.placement.from),i=false;t.addClass(this.settings.animate.exit);t.nextAll('[data-growl-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]').each(function(){e(this).css(n.placement.from,r);r=parseInt(r)+n.spacing+e(this).outerHeight()});t.one("webkitAnimationStart oanimationstart MSAnimationStart animationstart",function(e){i=true});t.one("webkitAnimationEnd oanimationend MSAnimationEnd animationend",function(t){e(this).remove()});setTimeout(function(){console.log(i);if(!i){t.remove()}},100);return this}};e.growl=function(e,t){if(e==false){u(this,t);return false}var n=new a(this,e,t);return n}})(jQuery,window,document) \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-growl/jquery.bootstrap-growl.min.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-growl/jquery.bootstrap-growl.min.js index 67837e50..0936670e 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-growl/jquery.bootstrap-growl.min.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-growl/jquery.bootstrap-growl.min.js @@ -1 +1 @@ -(function(){var c;c=jQuery;c.bootstrapGrowl=function(f,a){var b,e,d;a=c.extend({},c.bootstrapGrowl.default_options,a);b=c("
    ");b.attr("class","bootstrap-growl alert");a.type&&b.addClass("alert-"+a.type);a.allow_dismiss&&(b.addClass("alert-dismissible"),b.append(''));b.append(f);a.top_offset&&(a.offset={from:"top",amount:a.top_offset});d=a.offset.amount;c(".bootstrap-growl").each(function(){return d= Math.max(d,parseInt(c(this).css(a.offset.from))+c(this).outerHeight()+a.stackup_spacing)});e={position:"body"===a.ele?"fixed":"absolute",margin:0,"z-index":"9999",display:"none"};e[a.offset.from]=d+"px";b.css(e);"auto"!==a.width&&b.css("width",a.width+"px");c(a.ele).append(b);switch(a.align){case "center":b.css({left:"50%","margin-left":"-"+b.outerWidth()/2+"px"});break;case "left":b.css("left","20px");break;default:b.css("right","20px")}b.fadeIn();0");b.attr("class","bootstrap-growl alert");a.type&&b.addClass("alert-"+a.type);a.allow_dismiss&&(b.addClass("alert-dismissible"),b.append(''));b.append(f);a.top_offset&&(a.offset={from:"top",amount:a.top_offset});d=a.offset.amount;c(".bootstrap-growl").each(function(){return d= Math.max(d,parseInt(c(this).css(a.offset.from))+c(this).outerHeight()+a.stackup_spacing)});e={position:"body"===a.ele?"fixed":"absolute",margin:0,"z-index":"9999",display:"none"};e[a.offset.from]=d+"px";b.css(e);"auto"!==a.width&&b.css("width",a.width+"px");c(a.ele).append(b);switch(a.align){case "center":b.css({left:"50%","margin-left":"-"+b.outerWidth()/2+"px"});break;case "left":b.css("left","20px");break;default:b.css("right","20px")}b.fadeIn();0 - - - -``` - -## Usage - -Just like in Bootstrap you can activate it without any JavaScript, just by adding a data-attribute, you can make it automatically work. - -Add `data-hover="dropdown"` in addition (or in place of) Bootstrap's `data-toggle="dropdown"`. - -You can set options via data-attributes, too, via `data-delay` and `data-close-others`. Here's an example of markup: - -```html - -``` - -Alternatively, you can initialize via JavaScript: - -```javascript -$('.dropdown-toggle').dropdownHover(options); -``` - -This also works with submenus without any other configuring since Bootstrap already supports this feature. Just use the markup like you were using before. Only the top level anchor tag needs any special markup for my plugin to work (see demo for proper markup). - -## Options - -* **delay**: *(optional)* The delay in miliseconds. This is the time to wait before closing a dropdown when the mouse is no longer over the dropdown or the button/nav item that activated it. Defaults to `500`. -* **instantlyCloseOthers**: *(optional)* A boolean value that when true, will instantly close all other dropdowns matched by the selector used when you activate a new navigation. This is nice for when you have dropdowns close together that may overlap. Default is `true`. - -## Demo - -You can view a demo for this plugin on my site: http://cameronspear.com/demos/bootstrap-hover-dropdown/ - -### A Note on Choosing a Selector - -This plugin purposedly lets you choose a selector (as opposed to apply this to everything with the class of `.dropdown-toggle`). This is so that you can selectively apply it where you want. Maybe you only want to use it for the main nav, and not have it activate for dropdown buttons in the main content. You can add a class to the item that normally gets `.dropdown-toggle` and use that class with this plugin to easily achieve that, or use a selector such as `.main-nav .dropdown-toggle`. - -**Important:** Bootstrap relies on styles associated with the class `.dropdown-toggle` (for stuff like the caret color), and it is recommended you leave that class alone. - -## Changes/Bug Fixes - -I'm a slacker and only started keeping track of changes/bug fixes starting in March of 2013. - -* **2014-01-27** Fixed an issue where chaining could break on mobile and cleaned up the the way the plugin triggered events. Also cleaned up the demo (fixed navbar appearance). -* **2013-12-05** Change all references of *Twitter Bootstrap* to *Bootstrap* to reflect Bootstrap's name change. -* **2013-11-09** Disable this plugin for devices that support touch. The plugin was causing issues with some mobile devices, and it's not necessary for them. -* **2013-08-02** Add support for Bootstrap 3. For Bootstrap 2.x.x, use the `bootstrap-2.x.x` branch. -* **2013-06-10** Always instantly close submenu siblings when opening a new one. Issue #19. -* **2013-06-10** A fix for my last fix that would sometimes cause the correct item to not trigger when it should. Issue #18. -* **2013-05-08** Fix issue where a sibling could open a drop down that wasn't theirs. Issue #18. -* **2013-04-29** Added support for submenus: Submenus should now honor the delay option and way before closing. They do not abide by the `instantlyCloseOthers` option, as it's not really relevant. -* **2013-04-19** Fixed an issue where the conditional rule to disable hover on mobile wasn't working if you included the script in the header. -* **2013-04-03** Made it so if you're using the responsive CSS and in tablet/mobile view, disable the hover. -* **2013-03-16** Fixed an issue where the options you passed in via the method call were completely ignored. - -## Contributions - -[Mattia Larentis](https://github.com/nostalgiaz) helped me with the idea for the data-attributes and doing the options via an object. - -## Roadmap - -As this plugin, in its simplicity, is pretty much exactly what I intend it to be, I don't plan to implement any new features. ~~**One exception:** I would like to tweak it so that when you're in a submenu, it doesn't instantly close when you hover outside of it.~~ **Update:** I added this in late April 2013. - -If you have ideas for a new feature or something along those lines, you're welcome to share them with me, but I am not likely to implement it/merge your pull without a very compelling reason. You are absolutely free to create a fork and implement the feature yourself for your and others' use. - -This, of course, does not speak for bugs. If you have a bug, please bring it to my attention, and I will try and fix it. Note that 93.7% of people's issues are caused by incorrect markup, so please double check that first. - -## Me - -Follow me on Twitter: [@CWSpear](https://twitter.com/CWSpear) or check out my [blog](http://cameronspear.com/blog/). +Bootstrap Hover Dropdown Plugin +=============================== + +![Current Version](http://img.shields.io/github/tag/cwspear/bootstrap-hover-dropdown.svg?style=flat) + +#### Name Change + +*Twitter Bootstrap* is now just *Bootstrap*, and I've renamed this repo, **renamed the files** and change all references from *Twitter Bootstrap* to just *Bootstrap* in the docs/example to reflect that. + +No actual code changed, so I am keeping the current version (`2.0.1` at the time of this writing), but be aware of the lack of *twitter-* from the beginning of the JS files and how that might affect you. + +Sorry for any inconvenience! + +#### Updated for Bootstrap 3 + +I updated the demo with Bootstrap 3, as well as removed code associated to submenus ([not supported in Bootstrap 3](https://github.com/twbs/bootstrap/pull/6342#issuecomment-11594010)) and touch devices (just make sure you have `data-toggle="dropdown"` to let Mobile do its thing and my plugin won't interfere). + +## Introduction + +A simple plugin to enable Bootstrap dropdowns to activate on hover and provide a nice user experience. + +The dropdowns are dismissed after a configurable delay. This fixes an issue that can instantly close your nav because of a 1px gap between the button/nav item that activated the dropdown and the actual dropdown. It is also generally a better user experience, as users are not punished by going 1 pixel outside of the dropdown, which would instantly close the nav without a delay. + +**Note:** The HTML markup is the same as with any other Bootstrap dropdown. This will not interfere with Bootstrap's default activate-on-click method (i.e. this plugin combined with Bootstrap's default behavior work well to support both the ideal experience on desktop and mobile). + +## Installation + +You can simply download and extract the package downloaded from GitHub. Alternatively, you can download the files via [Bower](http://bower.io/) (a JavaScript package management system): + +``` +bower install bootstrap-hover-dropdown +``` + +which will also automatically install Bootstrap and jQuery if needed. + +Once you have the files downloaded, link to the files in your code *after* you include the main Bootstrap JS file(s): + +```html + + + + +``` + +## Usage + +Just like in Bootstrap you can activate it without any JavaScript, just by adding a data-attribute, you can make it automatically work. + +Add `data-hover="dropdown"` in addition (or in place of) Bootstrap's `data-toggle="dropdown"`. + +You can set options via data-attributes, too, via `data-delay` and `data-close-others`. Here's an example of markup: + +```html + +``` + +Alternatively, you can initialize via JavaScript: + +```javascript +$('.dropdown-toggle').dropdownHover(options); +``` + +This also works with submenus without any other configuring since Bootstrap already supports this feature. Just use the markup like you were using before. Only the top level anchor tag needs any special markup for my plugin to work (see demo for proper markup). + +## Options + +* **delay**: *(optional)* The delay in miliseconds. This is the time to wait before closing a dropdown when the mouse is no longer over the dropdown or the button/nav item that activated it. Defaults to `500`. +* **instantlyCloseOthers**: *(optional)* A boolean value that when true, will instantly close all other dropdowns matched by the selector used when you activate a new navigation. This is nice for when you have dropdowns close together that may overlap. Default is `true`. + +## Demo + +You can view a demo for this plugin on my site: http://cameronspear.com/demos/bootstrap-hover-dropdown/ + +### A Note on Choosing a Selector + +This plugin purposedly lets you choose a selector (as opposed to apply this to everything with the class of `.dropdown-toggle`). This is so that you can selectively apply it where you want. Maybe you only want to use it for the main nav, and not have it activate for dropdown buttons in the main content. You can add a class to the item that normally gets `.dropdown-toggle` and use that class with this plugin to easily achieve that, or use a selector such as `.main-nav .dropdown-toggle`. + +**Important:** Bootstrap relies on styles associated with the class `.dropdown-toggle` (for stuff like the caret color), and it is recommended you leave that class alone. + +## Changes/Bug Fixes + +I'm a slacker and only started keeping track of changes/bug fixes starting in March of 2013. + +* **2014-01-27** Fixed an issue where chaining could break on mobile and cleaned up the the way the plugin triggered events. Also cleaned up the demo (fixed navbar appearance). +* **2013-12-05** Change all references of *Twitter Bootstrap* to *Bootstrap* to reflect Bootstrap's name change. +* **2013-11-09** Disable this plugin for devices that support touch. The plugin was causing issues with some mobile devices, and it's not necessary for them. +* **2013-08-02** Add support for Bootstrap 3. For Bootstrap 2.x.x, use the `bootstrap-2.x.x` branch. +* **2013-06-10** Always instantly close submenu siblings when opening a new one. Issue #19. +* **2013-06-10** A fix for my last fix that would sometimes cause the correct item to not trigger when it should. Issue #18. +* **2013-05-08** Fix issue where a sibling could open a drop down that wasn't theirs. Issue #18. +* **2013-04-29** Added support for submenus: Submenus should now honor the delay option and way before closing. They do not abide by the `instantlyCloseOthers` option, as it's not really relevant. +* **2013-04-19** Fixed an issue where the conditional rule to disable hover on mobile wasn't working if you included the script in the header. +* **2013-04-03** Made it so if you're using the responsive CSS and in tablet/mobile view, disable the hover. +* **2013-03-16** Fixed an issue where the options you passed in via the method call were completely ignored. + +## Contributions + +[Mattia Larentis](https://github.com/nostalgiaz) helped me with the idea for the data-attributes and doing the options via an object. + +## Roadmap + +As this plugin, in its simplicity, is pretty much exactly what I intend it to be, I don't plan to implement any new features. ~~**One exception:** I would like to tweak it so that when you're in a submenu, it doesn't instantly close when you hover outside of it.~~ **Update:** I added this in late April 2013. + +If you have ideas for a new feature or something along those lines, you're welcome to share them with me, but I am not likely to implement it/merge your pull without a very compelling reason. You are absolutely free to create a fork and implement the feature yourself for your and others' use. + +This, of course, does not speak for bugs. If you have a bug, please bring it to my attention, and I will try and fix it. Note that 93.7% of people's issues are caused by incorrect markup, so please double check that first. + +## Me + +Follow me on Twitter: [@CWSpear](https://twitter.com/CWSpear) or check out my [blog](http://cameronspear.com/blog/). diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-hover-dropdown/bootstrap-hover-dropdown.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-hover-dropdown/bootstrap-hover-dropdown.js index fac00fdb..55c5aa21 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-hover-dropdown/bootstrap-hover-dropdown.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-hover-dropdown/bootstrap-hover-dropdown.js @@ -1,14 +1,14 @@ -/** - * Project: Bootstrap Hover Dropdown - * Author: Cameron Spear - * Contributors: Mattia Larentis - * - * Dependencies: Bootstrap's Dropdown plugin, jQuery - * - * A simple plugin to enable Bootstrap dropdowns to active on hover and provide a nice user experience. - * - * License: MIT - * - * http://cameronspear.com/blog/bootstrap-dropdown-on-hover-plugin/ - */ -!function(e,n){var o=e();e.fn.dropdownHover=function(t){return"ontouchstart"in document?this:(o=o.add(this.parent()),this.each(function(){var i,r=e(this),s=r.parent(),d={delay:500,instantlyCloseOthers:!0},a={delay:e(this).data("delay"),instantlyCloseOthers:e(this).data("close-others")},h="show.bs.dropdown",u="hide.bs.dropdown",l=e.extend(!0,{},d,t,a);s.hover(function(e){return s.hasClass("open")||r.is(e.target)?(o.find(":focus").blur(),l.instantlyCloseOthers===!0&&o.removeClass("open"),n.clearTimeout(i),s.addClass("open"),void r.trigger(h)):!0},function(){i=n.setTimeout(function(){s.removeClass("open"),r.trigger(u)},l.delay)}),r.hover(function(){o.find(":focus").blur(),l.instantlyCloseOthers===!0&&o.removeClass("open"),n.clearTimeout(i),s.addClass("open"),r.trigger(h)}),s.find(".dropdown-submenu").each(function(){var o,t=e(this);t.hover(function(){n.clearTimeout(o),t.children(".dropdown-menu").show(),t.siblings().children(".dropdown-menu").hide()},function(){var e=t.children(".dropdown-menu");o=n.setTimeout(function(){e.hide()},l.delay)})})}))},e(document).ready(function(){e('[data-hover="dropdown"]').not(".hover-initialized").each(function(){e(this).dropdownHover(),e(this).addClass("hover-initialized")})})}(jQuery,this); +/** + * Project: Bootstrap Hover Dropdown + * Author: Cameron Spear + * Contributors: Mattia Larentis + * + * Dependencies: Bootstrap's Dropdown plugin, jQuery + * + * A simple plugin to enable Bootstrap dropdowns to active on hover and provide a nice user experience. + * + * License: MIT + * + * http://cameronspear.com/blog/bootstrap-dropdown-on-hover-plugin/ + */ +!function(e,n){var o=e();e.fn.dropdownHover=function(t){return"ontouchstart"in document?this:(o=o.add(this.parent()),this.each(function(){var i,r=e(this),s=r.parent(),d={delay:500,instantlyCloseOthers:!0},a={delay:e(this).data("delay"),instantlyCloseOthers:e(this).data("close-others")},h="show.bs.dropdown",u="hide.bs.dropdown",l=e.extend(!0,{},d,t,a);s.hover(function(e){return s.hasClass("open")||r.is(e.target)?(o.find(":focus").blur(),l.instantlyCloseOthers===!0&&o.removeClass("open"),n.clearTimeout(i),s.addClass("open"),void r.trigger(h)):!0},function(){i=n.setTimeout(function(){s.removeClass("open"),r.trigger(u)},l.delay)}),r.hover(function(){o.find(":focus").blur(),l.instantlyCloseOthers===!0&&o.removeClass("open"),n.clearTimeout(i),s.addClass("open"),r.trigger(h)}),s.find(".dropdown-submenu").each(function(){var o,t=e(this);t.hover(function(){n.clearTimeout(o),t.children(".dropdown-menu").show(),t.siblings().children(".dropdown-menu").hide()},function(){var e=t.children(".dropdown-menu");o=n.setTimeout(function(){e.hide()},l.delay)})})}))},e(document).ready(function(){e('[data-hover="dropdown"]').not(".hover-initialized").each(function(){e(this).dropdownHover(),e(this).addClass("hover-initialized")})})}(jQuery,this); diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-hover-dropdown/bootstrap-hover-dropdown.min.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-hover-dropdown/bootstrap-hover-dropdown.min.js index 0bf4687b..25757af5 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-hover-dropdown/bootstrap-hover-dropdown.min.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-hover-dropdown/bootstrap-hover-dropdown.min.js @@ -1,13 +1,13 @@ -/** - * Project: Bootstrap Hover Dropdown - * Author: Cameron Spear - * Contributors: Mattia Larentis - * - * Dependencies: Bootstrap's Dropdown plugin, jQuery - * - * A simple plugin to enable Bootstrap dropdowns to active on hover and provide a nice user experience. - * - * License: MIT - * - * http://cameronspear.com/blog/bootstrap-dropdown-on-hover-plugin/ +/** + * Project: Bootstrap Hover Dropdown + * Author: Cameron Spear + * Contributors: Mattia Larentis + * + * Dependencies: Bootstrap's Dropdown plugin, jQuery + * + * A simple plugin to enable Bootstrap dropdowns to active on hover and provide a nice user experience. + * + * License: MIT + * + * http://cameronspear.com/blog/bootstrap-dropdown-on-hover-plugin/ */(function(b,a,c){var d=b();b.fn.dropdownHover=function(e){if("ontouchstart" in document){return this}d=d.add(this.parent());return this.each(function(){var m=b(this),l=m.parent(),k={delay:500,instantlyCloseOthers:true},i={delay:b(this).data("delay"),instantlyCloseOthers:b(this).data("close-others")},f="show.bs.dropdown",j="hide.bs.dropdown",g=b.extend(true,{},k,e,i),h;l.hover(function(n){if(!l.hasClass("open")&&!m.is(n.target)){return true}d.find(":focus").blur();if(g.instantlyCloseOthers===true){d.removeClass("open")}a.clearTimeout(h);l.addClass("open");m.trigger(f)},function(){h=a.setTimeout(function(){l.removeClass("open");m.trigger(j)},g.delay)});m.hover(function(){d.find(":focus").blur();if(g.instantlyCloseOthers===true){d.removeClass("open")}a.clearTimeout(h);l.addClass("open");m.trigger(f)});l.find(".dropdown-submenu").each(function(){var o=b(this);var n;o.hover(function(){a.clearTimeout(n);o.children(".dropdown-menu").show();o.siblings().children(".dropdown-menu").hide()},function(){var p=o.children(".dropdown-menu");n=a.setTimeout(function(){p.hide()},g.delay)})})})};b(document).ready(function(){b('[data-hover="dropdown"]').dropdownHover()})})(jQuery,this); \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/css/bootstrap-modal-bs3patch.css b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/css/bootstrap-modal-bs3patch.css index 71ca0edc..9939f3ce 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/css/bootstrap-modal-bs3patch.css +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/css/bootstrap-modal-bs3patch.css @@ -1,51 +1,51 @@ -/*! - * Bootstrap Modal - * - * Copyright Jordan Schroter - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Boostrap 3 patch for for bootstrap-modal. Include BEFORE bootstrap-modal.css! - */ - -body.modal-open, -.modal-open .navbar-fixed-top, -.modal-open .navbar-fixed-bottom { - margin-right: 0; -} - -.modal { - left: 50%; - bottom: auto; - right: auto; - z-index: 1050; - padding: 0; - width: 600px; - margin-left: -300px; - background-color: #ffffff; - border: 1px solid #999999; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 6px; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); - background-clip: padding-box; -} - -.modal.container { - max-width: none; -} - -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; -} - -.modal.bootbox { - border: none; - background: none; - box-shadow: none; +/*! + * Bootstrap Modal + * + * Copyright Jordan Schroter + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Boostrap 3 patch for for bootstrap-modal. Include BEFORE bootstrap-modal.css! + */ + +body.modal-open, +.modal-open .navbar-fixed-top, +.modal-open .navbar-fixed-bottom { + margin-right: 0; +} + +.modal { + left: 50%; + bottom: auto; + right: auto; + z-index: 1050; + padding: 0; + width: 600px; + margin-left: -300px; + background-color: #ffffff; + border: 1px solid #999999; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; +} + +.modal.container { + max-width: none; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; +} + +.modal.bootbox { + border: none; + background: none; + box-shadow: none; } \ No newline at end of file diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/css/bootstrap-modal.css b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/css/bootstrap-modal.css index 4e48f1cf..bc62761a 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/css/bootstrap-modal.css +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/css/bootstrap-modal.css @@ -1,214 +1,214 @@ -/*! - * Bootstrap Modal - * - * Copyright Jordan Schroter - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - */ - -.modal-open { - overflow: hidden; -} - - -/* add a scroll bar to stop page from jerking around */ -.modal-open.page-overflow .page-container, -.modal-open.page-overflow .page-container .navbar-fixed-top, -.modal-open.page-overflow .page-container .navbar-fixed-bottom, -.modal-open.page-overflow .modal-scrollable { - overflow-y: scroll; -} - -@media (max-width: 979px) { - .modal-open.page-overflow .page-container .navbar-fixed-top, - .modal-open.page-overflow .page-container .navbar-fixed-bottom { - overflow-y: visible; - } -} - - -.modal-scrollable { - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - overflow: auto; -} - -.modal { - outline: none; - position: absolute; - margin-top: 0; - top: 50%; - overflow: visible; /* allow content to popup out (i.e tooltips) */ -} - -.modal.fade { - top: -100%; - -webkit-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; - -moz-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; - -o-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; - transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; -} - -.modal.fade.in { - top: 50%; -} - -.modal-body { - max-height: none; - overflow: visible; -} - -.modal.modal-absolute { - position: absolute; - z-index: 950; -} - -.modal .loading-mask { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - background: #fff; - border-radius: 6px; -} - -.modal-backdrop.modal-absolute{ - position: absolute; - z-index: 940; -} - -.modal-backdrop, -.modal-backdrop.fade.in{ - opacity: 0.7; - filter: alpha(opacity=70); - background: #fff; -} - -.modal.container { - width: 940px; - margin-left: -470px; -} - -/* Modal Overflow */ - -.modal-overflow.modal { - top: 5%; -} - -.modal-overflow.modal.fade { - top: -100%; -} - -.modal-overflow.modal.fade.in { - top: 5%; -} - -.modal-overflow .modal-body { - overflow: auto; - -webkit-overflow-scrolling: touch; -} - -/* Responsive */ - -@media (min-width: 1200px) { - .modal.container { - width: 1170px; - margin-left: -585px; - } -} - -@media (max-width: 979px) { - .modal, - .modal.container, - .modal.modal-overflow { - top: 1%; - right: 1%; - left: 1%; - bottom: auto; - width: auto !important; - height: auto !important; - margin: 0 !important; - padding: 0 !important; - } - - .modal.fade.in, - .modal.container.fade.in, - .modal.modal-overflow.fade.in { - top: 1%; - bottom: auto; - } - - .modal-body, - .modal-overflow .modal-body { - position: static; - margin: 0; - height: auto !important; - max-height: none !important; - overflow: visible !important; - } - - .modal-footer, - .modal-overflow .modal-footer { - position: static; - } -} - -.loading-spinner { - position: absolute; - top: 50%; - left: 50%; - margin: -12px 0 0 -12px; -} - -/* -Animate.css - http://daneden.me/animate -Licensed under the ☺ license (http://licence.visualidiot.com/) - -Copyright (c) 2012 Dan Eden*/ - -.animated { - -webkit-animation-duration: 1s; - -moz-animation-duration: 1s; - -o-animation-duration: 1s; - animation-duration: 1s; - -webkit-animation-fill-mode: both; - -moz-animation-fill-mode: both; - -o-animation-fill-mode: both; - animation-fill-mode: both; -} - -@-webkit-keyframes shake { - 0%, 100% {-webkit-transform: translateX(0);} - 10%, 30%, 50%, 70%, 90% {-webkit-transform: translateX(-10px);} - 20%, 40%, 60%, 80% {-webkit-transform: translateX(10px);} -} - -@-moz-keyframes shake { - 0%, 100% {-moz-transform: translateX(0);} - 10%, 30%, 50%, 70%, 90% {-moz-transform: translateX(-10px);} - 20%, 40%, 60%, 80% {-moz-transform: translateX(10px);} -} - -@-o-keyframes shake { - 0%, 100% {-o-transform: translateX(0);} - 10%, 30%, 50%, 70%, 90% {-o-transform: translateX(-10px);} - 20%, 40%, 60%, 80% {-o-transform: translateX(10px);} -} - -@keyframes shake { - 0%, 100% {transform: translateX(0);} - 10%, 30%, 50%, 70%, 90% {transform: translateX(-10px);} - 20%, 40%, 60%, 80% {transform: translateX(10px);} -} - -.shake { - -webkit-animation-name: shake; - -moz-animation-name: shake; - -o-animation-name: shake; - animation-name: shake; -} +/*! + * Bootstrap Modal + * + * Copyright Jordan Schroter + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ + +.modal-open { + overflow: hidden; +} + + +/* add a scroll bar to stop page from jerking around */ +.modal-open.page-overflow .page-container, +.modal-open.page-overflow .page-container .navbar-fixed-top, +.modal-open.page-overflow .page-container .navbar-fixed-bottom, +.modal-open.page-overflow .modal-scrollable { + overflow-y: scroll; +} + +@media (max-width: 979px) { + .modal-open.page-overflow .page-container .navbar-fixed-top, + .modal-open.page-overflow .page-container .navbar-fixed-bottom { + overflow-y: visible; + } +} + + +.modal-scrollable { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + overflow: auto; +} + +.modal { + outline: none; + position: absolute; + margin-top: 0; + top: 50%; + overflow: visible; /* allow content to popup out (i.e tooltips) */ +} + +.modal.fade { + top: -100%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; +} + +.modal.fade.in { + top: 50%; +} + +.modal-body { + max-height: none; + overflow: visible; +} + +.modal.modal-absolute { + position: absolute; + z-index: 950; +} + +.modal .loading-mask { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background: #fff; + border-radius: 6px; +} + +.modal-backdrop.modal-absolute{ + position: absolute; + z-index: 940; +} + +.modal-backdrop, +.modal-backdrop.fade.in{ + opacity: 0.7; + filter: alpha(opacity=70); + background: #fff; +} + +.modal.container { + width: 940px; + margin-left: -470px; +} + +/* Modal Overflow */ + +.modal-overflow.modal { + top: 5%; +} + +.modal-overflow.modal.fade { + top: -100%; +} + +.modal-overflow.modal.fade.in { + top: 5%; +} + +.modal-overflow .modal-body { + overflow: auto; + -webkit-overflow-scrolling: touch; +} + +/* Responsive */ + +@media (min-width: 1200px) { + .modal.container { + width: 1170px; + margin-left: -585px; + } +} + +@media (max-width: 979px) { + .modal, + .modal.container, + .modal.modal-overflow { + top: 1%; + right: 1%; + left: 1%; + bottom: auto; + width: auto !important; + height: auto !important; + margin: 0 !important; + padding: 0 !important; + } + + .modal.fade.in, + .modal.container.fade.in, + .modal.modal-overflow.fade.in { + top: 1%; + bottom: auto; + } + + .modal-body, + .modal-overflow .modal-body { + position: static; + margin: 0; + height: auto !important; + max-height: none !important; + overflow: visible !important; + } + + .modal-footer, + .modal-overflow .modal-footer { + position: static; + } +} + +.loading-spinner { + position: absolute; + top: 50%; + left: 50%; + margin: -12px 0 0 -12px; +} + +/* +Animate.css - http://daneden.me/animate +Licensed under the ☺ license (http://licence.visualidiot.com/) + +Copyright (c) 2012 Dan Eden*/ + +.animated { + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + -o-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + -moz-animation-fill-mode: both; + -o-animation-fill-mode: both; + animation-fill-mode: both; +} + +@-webkit-keyframes shake { + 0%, 100% {-webkit-transform: translateX(0);} + 10%, 30%, 50%, 70%, 90% {-webkit-transform: translateX(-10px);} + 20%, 40%, 60%, 80% {-webkit-transform: translateX(10px);} +} + +@-moz-keyframes shake { + 0%, 100% {-moz-transform: translateX(0);} + 10%, 30%, 50%, 70%, 90% {-moz-transform: translateX(-10px);} + 20%, 40%, 60%, 80% {-moz-transform: translateX(10px);} +} + +@-o-keyframes shake { + 0%, 100% {-o-transform: translateX(0);} + 10%, 30%, 50%, 70%, 90% {-o-transform: translateX(-10px);} + 20%, 40%, 60%, 80% {-o-transform: translateX(10px);} +} + +@keyframes shake { + 0%, 100% {transform: translateX(0);} + 10%, 30%, 50%, 70%, 90% {transform: translateX(-10px);} + 20%, 40%, 60%, 80% {transform: translateX(10px);} +} + +.shake { + -webkit-animation-name: shake; + -moz-animation-name: shake; + -o-animation-name: shake; + animation-name: shake; +} diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/js/bootstrap-modal.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/js/bootstrap-modal.js index 58da13a8..20bb29c8 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/js/bootstrap-modal.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/bootstrap-modal/js/bootstrap-modal.js @@ -1,378 +1,378 @@ -/* =========================================================== - * bootstrap-modal.js v2.2.5 - * =========================================================== - * Copyright 2012 Jordan Schroter - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================== */ - - -!function ($) { - - "use strict"; // jshint ;_; - - /* MODAL CLASS DEFINITION - * ====================== */ - - var Modal = function (element, options) { - this.init(element, options); - }; - - Modal.prototype = { - - constructor: Modal, - - init: function (element, options) { - var that = this; - - this.options = options; - - this.$element = $(element) - .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)); - - this.options.remote && this.$element.find('.modal-body').load(this.options.remote, function () { - var e = $.Event('loaded'); - that.$element.trigger(e); - }); - - var manager = typeof this.options.manager === 'function' ? - this.options.manager.call(this) : this.options.manager; - - manager = manager.appendModal ? - manager : $(manager).modalmanager().data('modalmanager'); - - manager.appendModal(this); - }, - - toggle: function () { - return this[!this.isShown ? 'show' : 'hide'](); - }, - - show: function () { - var e = $.Event('show'); - - if (this.isShown) return; - - this.$element.trigger(e); - - if (e.isDefaultPrevented()) return; - - this.escape(); - - this.tab(); - - this.options.loading && this.loading(); - }, - - hide: function (e) { - e && e.preventDefault(); - - e = $.Event('hide'); - - this.$element.trigger(e); - - if (!this.isShown || e.isDefaultPrevented()) return; - - this.isShown = false; - - this.escape(); - - this.tab(); - - this.isLoading && this.loading(); - - $(document).off('focusin.modal'); - - this.$element - .removeClass('in') - .removeClass('animated') - .removeClass(this.options.attentionAnimation) - .removeClass('modal-overflow') - .attr('aria-hidden', true); - - $.support.transition && this.$element.hasClass('fade') ? - this.hideWithTransition() : - this.hideModal(); - }, - - layout: function () { - var prop = this.options.height ? 'height' : 'max-height', - value = this.options.height || this.options.maxHeight; - - if (this.options.width){ - this.$element.css('width', this.options.width); - - var that = this; - this.$element.css('margin-left', function () { - if (/%/ig.test(that.options.width)){ - return -(parseInt(that.options.width) / 2) + '%'; - } else { - return -($(this).width() / 2) + 'px'; - } - }); - } else { - this.$element.css('width', ''); - this.$element.css('margin-left', ''); - } - - this.$element.find('.modal-body') - .css('overflow', '') - .css(prop, ''); - - if (value){ - this.$element.find('.modal-body') - .css('overflow', 'auto') - .css(prop, value); - } - - var modalOverflow = $(window).height() - 10 < this.$element.height(); - - if (modalOverflow || this.options.modalOverflow) { - this.$element - .css('margin-top', 0) - .addClass('modal-overflow'); - } else { - this.$element - .css('margin-top', 0 - this.$element.height() / 2) - .removeClass('modal-overflow'); - } - }, - - tab: function () { - var that = this; - - if (this.isShown && this.options.consumeTab) { - this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) { - if (e.keyCode && e.keyCode == 9){ - var elements = [], - tabindex = Number($(this).data('tabindex')); - - that.$element.find('[data-tabindex]:enabled:visible:not([readonly])').each(function (ev) { - elements.push(Number($(this).data('tabindex'))); - }); - elements.sort(function(a,b){return a-b}); - - var arrayPos = $.inArray(tabindex, elements); - if (!e.shiftKey){ - arrayPos < elements.length-1 ? - that.$element.find('[data-tabindex='+elements[arrayPos+1]+']').focus() : - that.$element.find('[data-tabindex='+elements[0]+']').focus(); - } else { - arrayPos == 0 ? - that.$element.find('[data-tabindex='+elements[elements.length-1]+']').focus() : - that.$element.find('[data-tabindex='+elements[arrayPos-1]+']').focus(); - } - - e.preventDefault(); - } - }); - } else if (!this.isShown) { - this.$element.off('keydown.tabindex.modal'); - } - }, - - escape: function () { - var that = this; - if (this.isShown && this.options.keyboard) { - if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1); - - this.$element.on('keyup.dismiss.modal', function (e) { - e.which == 27 && that.hide(); - }); - } else if (!this.isShown) { - this.$element.off('keyup.dismiss.modal') - } - }, - - hideWithTransition: function () { - var that = this - , timeout = setTimeout(function () { - that.$element.off($.support.transition.end); - that.hideModal(); - }, 500); - - this.$element.one($.support.transition.end, function () { - clearTimeout(timeout); - that.hideModal(); - }); - }, - - hideModal: function () { - var prop = this.options.height ? 'height' : 'max-height'; - var value = this.options.height || this.options.maxHeight; - - if (value){ - this.$element.find('.modal-body') - .css('overflow', '') - .css(prop, ''); - } - - this.$element - .hide() - .trigger('hidden'); - }, - - removeLoading: function () { - this.$loading.remove(); - this.$loading = null; - this.isLoading = false; - }, - - loading: function (callback) { - callback = callback || function () {}; - - var animate = this.$element.hasClass('fade') ? 'fade' : ''; - - if (!this.isLoading) { - var doAnimate = $.support.transition && animate; - - this.$loading = $('
    ') - .append(this.options.spinner) - .appendTo(this.$element); - - if (doAnimate) this.$loading[0].offsetWidth; // force reflow - - this.$loading.addClass('in'); - - this.isLoading = true; - - doAnimate ? - this.$loading.one($.support.transition.end, callback) : - callback(); - - } else if (this.isLoading && this.$loading) { - this.$loading.removeClass('in'); - - var that = this; - $.support.transition && this.$element.hasClass('fade')? - this.$loading.one($.support.transition.end, function () { that.removeLoading() }) : - that.removeLoading(); - - } else if (callback) { - callback(this.isLoading); - } - }, - - focus: function () { - var $focusElem = this.$element.find(this.options.focusOn); - - $focusElem = $focusElem.length ? $focusElem : this.$element; - - $focusElem.focus(); - }, - - attention: function (){ - // NOTE: transitionEnd with keyframes causes odd behaviour - - if (this.options.attentionAnimation){ - this.$element - .removeClass('animated') - .removeClass(this.options.attentionAnimation); - - var that = this; - - setTimeout(function () { - that.$element - .addClass('animated') - .addClass(that.options.attentionAnimation); - }, 0); - } - - - this.focus(); - }, - - - destroy: function () { - var e = $.Event('destroy'); - - this.$element.trigger(e); - - if (e.isDefaultPrevented()) return; - - this.$element - .off('.modal') - .removeData('modal') - .removeClass('in') - .attr('aria-hidden', true); - - if (this.$parent !== this.$element.parent()) { - this.$element.appendTo(this.$parent); - } else if (!this.$parent.length) { - // modal is not part of the DOM so remove it. - this.$element.remove(); - this.$element = null; - } - - this.$element.trigger('destroyed'); - } - }; - - - /* MODAL PLUGIN DEFINITION - * ======================= */ - - $.fn.modal = function (option, args) { - return this.each(function () { - var $this = $(this), - data = $this.data('modal'), - options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option); - - if (!data) $this.data('modal', (data = new Modal(this, options))); - if (typeof option == 'string') data[option].apply(data, [].concat(args)); - else if (options.show) data.show() - }) - }; - - $.fn.modal.defaults = { - keyboard: true, - backdrop: true, - loading: false, - show: true, - width: null, - height: null, - maxHeight: null, - modalOverflow: false, - consumeTab: true, - focusOn: null, - replace: false, - resize: false, - attentionAnimation: 'shake', - manager: 'body', - spinner: '
    ', - backdropTemplate: '')[0]; - oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable ); - - /* - * All DataTables are wrapped in a div - */ - oSettings.nTableWrapper = $('
    ')[0]; - oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; - - /* Track where we want to insert the option */ - var nInsertNode = oSettings.nTableWrapper; - - /* Loop over the user set positioning and place the elements as needed */ - var aDom = oSettings.sDom.split(''); - var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j; - for ( var i=0 ; i
    ')[0]; - - /* Check to see if we should append an id and/or a class name to the container */ - cNext = aDom[i+1]; - if ( cNext == "'" || cNext == '"' ) - { - sAttr = ""; - j = 2; - while ( aDom[i+j] != cNext ) - { - sAttr += aDom[i+j]; - j++; - } - - /* Replace jQuery UI constants */ - if ( sAttr == "H" ) - { - sAttr = oSettings.oClasses.sJUIHeader; - } - else if ( sAttr == "F" ) - { - sAttr = oSettings.oClasses.sJUIFooter; - } - - /* The attribute can be in the format of "#id.class", "#id" or "class" This logic - * breaks the string into parts and applies them as needed - */ - if ( sAttr.indexOf('.') != -1 ) - { - var aSplit = sAttr.split('.'); - nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); - nNewNode.className = aSplit[1]; - } - else if ( sAttr.charAt(0) == "#" ) - { - nNewNode.id = sAttr.substr(1, sAttr.length-1); - } - else - { - nNewNode.className = sAttr; - } - - i += j; /* Move along the position array */ - } - - nInsertNode.appendChild( nNewNode ); - nInsertNode = nNewNode; - } - else if ( cOption == '>' ) - { - /* End container div */ - nInsertNode = nInsertNode.parentNode; - } - else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange ) - { - /* Length */ - nTmp = _fnFeatureHtmlLength( oSettings ); - iPushFeature = 1; - } - else if ( cOption == 'f' && oSettings.oFeatures.bFilter ) - { - /* Filter */ - nTmp = _fnFeatureHtmlFilter( oSettings ); - iPushFeature = 1; - } - else if ( cOption == 'r' && oSettings.oFeatures.bProcessing ) - { - /* pRocessing */ - nTmp = _fnFeatureHtmlProcessing( oSettings ); - iPushFeature = 1; - } - else if ( cOption == 't' ) - { - /* Table */ - nTmp = _fnFeatureHtmlTable( oSettings ); - iPushFeature = 1; - } - else if ( cOption == 'i' && oSettings.oFeatures.bInfo ) - { - /* Info */ - nTmp = _fnFeatureHtmlInfo( oSettings ); - iPushFeature = 1; - } - else if ( cOption == 'p' && oSettings.oFeatures.bPaginate ) - { - /* Pagination */ - nTmp = _fnFeatureHtmlPaginate( oSettings ); - iPushFeature = 1; - } - else if ( DataTable.ext.aoFeatures.length !== 0 ) - { - /* Plug-in features */ - var aoFeatures = DataTable.ext.aoFeatures; - for ( var k=0, kLen=aoFeatures.length ; k') : - sSearchStr==="" ? '' : sSearchStr+' '; - - var nFilter = document.createElement( 'div' ); - nFilter.className = oSettings.oClasses.sFilter; - nFilter.innerHTML = ''; - if ( !oSettings.aanFeatures.f ) - { - nFilter.id = oSettings.sTableId+'_filter'; - } - - var jqFilter = $('input[type="text"]', nFilter); - - // Store a reference to the input element, so other input elements could be - // added to the filter wrapper if needed (submit button for example) - nFilter._DT_Input = jqFilter[0]; - - jqFilter.val( oPreviousSearch.sSearch.replace('"','"') ); - jqFilter.bind( 'keyup.DT', function(e) { - /* Update all other filter input elements for the new display */ - var n = oSettings.aanFeatures.f; - var val = this.value==="" ? "" : this.value; // mental IE8 fix :-( - - for ( var i=0, iLen=n.length ; i=0 ; i-- ) - { - var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ), - oSettings.aoColumns[iColumn].sType ); - if ( ! rpSearch.test( sData ) ) - { - oSettings.aiDisplay.splice( i, 1 ); - iIndexCorrector++; - } - } - } - - - /** - * Filter the data table based on user input and draw the table - * @param {object} oSettings dataTables settings object - * @param {string} sInput string to filter on - * @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0) - * @param {bool} bRegex treat as a regular expression or not - * @param {bool} bSmart perform smart filtering or not - * @param {bool} bCaseInsensitive Do case insenstive matching or not - * @memberof DataTable#oApi - */ - function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive ) - { - var i; - var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive ); - var oPrevSearch = oSettings.oPreviousSearch; - - /* Check if we are forcing or not - optional parameter */ - if ( !iForce ) - { - iForce = 0; - } - - /* Need to take account of custom filtering functions - always filter */ - if ( DataTable.ext.afnFiltering.length !== 0 ) - { - iForce = 1; - } - - /* - * If the input is blank - we want the full data set - */ - if ( sInput.length <= 0 ) - { - oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length); - oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); - } - else - { - /* - * We are starting a new search or the new search string is smaller - * then the old one (i.e. delete). Search from the master array - */ - if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length || - oPrevSearch.sSearch.length > sInput.length || iForce == 1 || - sInput.indexOf(oPrevSearch.sSearch) !== 0 ) - { - /* Nuke the old display array - we are going to rebuild it */ - oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length); - - /* Force a rebuild of the search array */ - _fnBuildSearchArray( oSettings, 1 ); - - /* Search through all records to populate the search array - * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 - * mapping - */ - for ( i=0 ; i').html(sSearch).text(); - } - - // Strip newline characters - return sSearch.replace( /[\n\r]/g, " " ); - } - - /** - * Build a regular expression object suitable for searching a table - * @param {string} sSearch string to search for - * @param {bool} bRegex treat as a regular expression or not - * @param {bool} bSmart perform smart filtering or not - * @param {bool} bCaseInsensitive Do case insensitive matching or not - * @returns {RegExp} constructed object - * @memberof DataTable#oApi - */ - function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive ) - { - var asSearch, sRegExpString; - - if ( bSmart ) - { - /* Generate the regular expression to use. Something along the lines of: - * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$ - */ - asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' ); - sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$'; - return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" ); - } - else - { - sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch ); - return new RegExp( sSearch, bCaseInsensitive ? "i" : "" ); - } - } - - - /** - * Convert raw data into something that the user can search on - * @param {string} sData data to be modified - * @param {string} sType data type - * @returns {string} search string - * @memberof DataTable#oApi - */ - function _fnDataToSearch ( sData, sType ) - { - if ( typeof DataTable.ext.ofnSearch[sType] === "function" ) - { - return DataTable.ext.ofnSearch[sType]( sData ); - } - else if ( sData === null ) - { - return ''; - } - else if ( sType == "html" ) - { - return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" ); - } - else if ( typeof sData === "string" ) - { - return sData.replace(/[\r\n]/g," "); - } - return sData; - } - - - /** - * scape a string such that it can be used in a regular expression - * @param {string} sVal string to escape - * @returns {string} escaped string - * @memberof DataTable#oApi - */ - function _fnEscapeRegex ( sVal ) - { - var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ]; - var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' ); - return sVal.replace(reReplace, '\\$1'); - } - - - /** - * Generate the node required for the info display - * @param {object} oSettings dataTables settings object - * @returns {node} Information element - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlInfo ( oSettings ) - { - var nInfo = document.createElement( 'div' ); - nInfo.className = oSettings.oClasses.sInfo; - - /* Actions that are to be taken once only for this feature */ - if ( !oSettings.aanFeatures.i ) - { - /* Add draw callback */ - oSettings.aoDrawCallback.push( { - "fn": _fnUpdateInfo, - "sName": "information" - } ); - - /* Add id */ - nInfo.id = oSettings.sTableId+'_info'; - } - oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' ); - - return nInfo; - } - - - /** - * Update the information elements in the display - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnUpdateInfo ( oSettings ) - { - /* Show information about the table */ - if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 ) - { - return; - } - - var - oLang = oSettings.oLanguage, - iStart = oSettings._iDisplayStart+1, - iEnd = oSettings.fnDisplayEnd(), - iMax = oSettings.fnRecordsTotal(), - iTotal = oSettings.fnRecordsDisplay(), - sOut; - - if ( iTotal === 0 ) - { - /* Empty record set */ - sOut = oLang.sInfoEmpty; - } - else { - /* Normal record set */ - sOut = oLang.sInfo; - } - - if ( iTotal != iMax ) - { - /* Record set after filtering */ - sOut += ' ' + oLang.sInfoFiltered; - } - - // Convert the macros - sOut += oLang.sInfoPostFix; - sOut = _fnInfoMacros( oSettings, sOut ); - - if ( oLang.fnInfoCallback !== null ) - { - sOut = oLang.fnInfoCallback.call( oSettings.oInstance, - oSettings, iStart, iEnd, iMax, iTotal, sOut ); - } - - var n = oSettings.aanFeatures.i; - for ( var i=0, iLen=n.length ; i'; - var i, iLen; - var aLengthMenu = oSettings.aLengthMenu; - - if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' && - typeof aLengthMenu[1] === 'object' ) - { - for ( i=0, iLen=aLengthMenu[0].length ; i'+aLengthMenu[1][i]+''; - } - } - else - { - for ( i=0, iLen=aLengthMenu.length ; i'+aLengthMenu[i]+''; - } - } - sStdMenu += ''; - - var nLength = document.createElement( 'div' ); - if ( !oSettings.aanFeatures.l ) - { - nLength.id = oSettings.sTableId+'_length'; - } - nLength.className = oSettings.oClasses.sLength; - nLength.innerHTML = ''; - - /* - * Set the length to the current display length - thanks to Andrea Pavlovic for this fix, - * and Stefan Skopnik for fixing the fix! - */ - $('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true); - - $('select', nLength).bind( 'change.DT', function(e) { - var iVal = $(this).val(); - - /* Update all other length options for the new display */ - var n = oSettings.aanFeatures.l; - for ( i=0, iLen=n.length ; i oSettings.aiDisplay.length || - oSettings._iDisplayLength == -1 ) - { - oSettings._iDisplayEnd = oSettings.aiDisplay.length; - } - else - { - oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength; - } - } - } - - - - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Note that most of the paging logic is done in - * DataTable.ext.oPagination - */ - - /** - * Generate the node required for default pagination - * @param {object} oSettings dataTables settings object - * @returns {node} Pagination feature node - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlPaginate ( oSettings ) - { - if ( oSettings.oScroll.bInfinite ) - { - return null; - } - - var nPaginate = document.createElement( 'div' ); - nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType; - - DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, - function( oSettings ) { - _fnCalculateEnd( oSettings ); - _fnDraw( oSettings ); - } - ); - - /* Add a draw callback for the pagination on first instance, to update the paging display */ - if ( !oSettings.aanFeatures.p ) - { - oSettings.aoDrawCallback.push( { - "fn": function( oSettings ) { - DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) { - _fnCalculateEnd( oSettings ); - _fnDraw( oSettings ); - } ); - }, - "sName": "pagination" - } ); - } - return nPaginate; - } - - - /** - * Alter the display settings to change the page - * @param {object} oSettings dataTables settings object - * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" - * or page number to jump to (integer) - * @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1 - * @memberof DataTable#oApi - */ - function _fnPageChange ( oSettings, mAction ) - { - var iOldStart = oSettings._iDisplayStart; - - if ( typeof mAction === "number" ) - { - oSettings._iDisplayStart = mAction * oSettings._iDisplayLength; - if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() ) - { - oSettings._iDisplayStart = 0; - } - } - else if ( mAction == "first" ) - { - oSettings._iDisplayStart = 0; - } - else if ( mAction == "previous" ) - { - oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ? - oSettings._iDisplayStart - oSettings._iDisplayLength : - 0; - - /* Correct for under-run */ - if ( oSettings._iDisplayStart < 0 ) - { - oSettings._iDisplayStart = 0; - } - } - else if ( mAction == "next" ) - { - if ( oSettings._iDisplayLength >= 0 ) - { - /* Make sure we are not over running the display array */ - if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() ) - { - oSettings._iDisplayStart += oSettings._iDisplayLength; - } - } - else - { - oSettings._iDisplayStart = 0; - } - } - else if ( mAction == "last" ) - { - if ( oSettings._iDisplayLength >= 0 ) - { - var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1; - oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength; - } - else - { - oSettings._iDisplayStart = 0; - } - } - else - { - _fnLog( oSettings, 0, "Unknown paging action: "+mAction ); - } - $(oSettings.oInstance).trigger('page', oSettings); - - return iOldStart != oSettings._iDisplayStart; - } - - - - /** - * Generate the node required for the processing node - * @param {object} oSettings dataTables settings object - * @returns {node} Processing element - * @memberof DataTable#oApi - */ - function _fnFeatureHtmlProcessing ( oSettings ) - { - var nProcessing = document.createElement( 'div' ); - - if ( !oSettings.aanFeatures.r ) - { - nProcessing.id = oSettings.sTableId+'_processing'; - } - nProcessing.innerHTML = oSettings.oLanguage.sProcessing; - nProcessing.className = oSettings.oClasses.sProcessing; - oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable ); - - return nProcessing; - } - - - /** - * Display or hide the processing indicator - * @param {object} oSettings dataTables settings object - * @param {bool} bShow Show the processing indicator (true) or not (false) - * @memberof DataTable#oApi - */ - function _fnProcessingDisplay ( oSettings, bShow ) - { - if ( oSettings.oFeatures.bProcessing ) - { - var an = oSettings.aanFeatures.r; - for ( var i=0, iLen=an.length ; i 0 ) - { - nCaption = nCaption[0]; - if ( nCaption._captionSide === "top" ) - { - nScrollHeadTable.appendChild( nCaption ); - } - else if ( nCaption._captionSide === "bottom" && nTfoot ) - { - nScrollFootTable.appendChild( nCaption ); - } - } - - /* - * Sizing - */ - /* When x-scrolling add the width and a scroller to move the header with the body */ - if ( oSettings.oScroll.sX !== "" ) - { - nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX ); - nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX ); - - if ( nTfoot !== null ) - { - nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX ); - } - - /* When the body is scrolled, then we also want to scroll the headers */ - $(nScrollBody).scroll( function (e) { - nScrollHead.scrollLeft = this.scrollLeft; - - if ( nTfoot !== null ) - { - nScrollFoot.scrollLeft = this.scrollLeft; - } - } ); - } - - /* When yscrolling, add the height */ - if ( oSettings.oScroll.sY !== "" ) - { - nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY ); - } - - /* Redraw - align columns across the tables */ - oSettings.aoDrawCallback.push( { - "fn": _fnScrollDraw, - "sName": "scrolling" - } ); - - /* Infinite scrolling event handlers */ - if ( oSettings.oScroll.bInfinite ) - { - $(nScrollBody).scroll( function() { - /* Use a blocker to stop scrolling from loading more data while other data is still loading */ - if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 ) - { - /* Check if we should load the next data set */ - if ( $(this).scrollTop() + $(this).height() > - $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap ) - { - /* Only do the redraw if we have to - we might be at the end of the data */ - if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() ) - { - _fnPageChange( oSettings, 'next' ); - _fnCalculateEnd( oSettings ); - _fnDraw( oSettings ); - } - } - } - } ); - } - - oSettings.nScrollHead = nScrollHead; - oSettings.nScrollFoot = nScrollFoot; - - return nScroller; - } - - - /** - * Update the various tables for resizing. It's a bit of a pig this function, but - * basically the idea to: - * 1. Re-create the table inside the scrolling div - * 2. Take live measurements from the DOM - * 3. Apply the measurements - * 4. Clean up - * @param {object} o dataTables settings object - * @returns {node} Node to add to the DOM - * @memberof DataTable#oApi - */ - function _fnScrollDraw ( o ) - { - var - nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0], - nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0], - nScrollBody = o.nTable.parentNode, - i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis, - nTheadSize, nTfootSize, - iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth, - nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null, - nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null, - ie67 = o.oBrowser.bScrollOversize, - zeroOut = function(nSizer) { - oStyle = nSizer.style; - oStyle.paddingTop = "0"; - oStyle.paddingBottom = "0"; - oStyle.borderTopWidth = "0"; - oStyle.borderBottomWidth = "0"; - oStyle.height = 0; - }; - - /* - * 1. Re-create the table inside the scrolling div - */ - - /* Remove the old minimised thead and tfoot elements in the inner table */ - $(o.nTable).children('thead, tfoot').remove(); - - /* Clone the current header and footer elements and then place it into the inner table */ - nTheadSize = $(o.nTHead).clone()[0]; - o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] ); - anHeadToSize = o.nTHead.getElementsByTagName('tr'); - anHeadSizers = nTheadSize.getElementsByTagName('tr'); - - if ( o.nTFoot !== null ) - { - nTfootSize = $(o.nTFoot).clone()[0]; - o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] ); - anFootToSize = o.nTFoot.getElementsByTagName('tr'); - anFootSizers = nTfootSize.getElementsByTagName('tr'); - } - - /* - * 2. Take live measurements from the DOM - do not alter the DOM itself! - */ - - /* Remove old sizing and apply the calculated column widths - * Get the unique column headers in the newly created (cloned) header. We want to apply the - * calculated sizes to this header - */ - if ( o.oScroll.sX === "" ) - { - nScrollBody.style.width = '100%'; - nScrollHeadInner.parentNode.style.width = '100%'; - } - - var nThs = _fnGetUniqueThs( o, nTheadSize ); - for ( i=0, iLen=nThs.length ; i nScrollBody.offsetHeight || - $(nScrollBody).css('overflow-y') == "scroll") ) - { - o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth); - } - } - else - { - if ( o.oScroll.sXInner !== "" ) - { - /* x scroll inner has been given - use it */ - o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner); - } - else if ( iSanityWidth == $(nScrollBody).width() && - $(nScrollBody).height() < $(o.nTable).height() ) - { - /* There is y-scrolling - try to take account of the y scroll bar */ - o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth ); - if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth ) - { - /* Not possible to take account of it */ - o.nTable.style.width = _fnStringToCss( iSanityWidth ); - } - } - else - { - /* All else fails */ - o.nTable.style.width = _fnStringToCss( iSanityWidth ); - } - } - - /* Recalculate the sanity width - now that we've applied the required width, before it was - * a temporary variable. This is required because the column width calculation is done - * before this table DOM is created. - */ - iSanityWidth = $(o.nTable).outerWidth(); - - /* We want the hidden header to have zero height, so remove padding and borders. Then - * set the width based on the real headers - */ - - // Apply all styles in one pass. Invalidates layout only once because we don't read any - // DOM properties. - _fnApplyToChildren( zeroOut, anHeadSizers ); - - // Read all widths in next pass. Forces layout only once because we do not change - // any DOM properties. - _fnApplyToChildren( function(nSizer) { - aApplied.push( _fnStringToCss( $(nSizer).width() ) ); - }, anHeadSizers ); - - // Apply all widths in final pass. Invalidates layout only once because we do not - // read any DOM properties. - _fnApplyToChildren( function(nToSize, i) { - nToSize.style.width = aApplied[i]; - }, anHeadToSize ); - - $(anHeadSizers).height(0); - - /* Same again with the footer if we have one */ - if ( o.nTFoot !== null ) - { - _fnApplyToChildren( zeroOut, anFootSizers ); - - _fnApplyToChildren( function(nSizer) { - aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) ); - }, anFootSizers ); - - _fnApplyToChildren( function(nToSize, i) { - nToSize.style.width = aAppliedFooter[i]; - }, anFootToSize ); - - $(anFootSizers).height(0); - } - - /* - * 3. Apply the measurements - */ - - /* "Hide" the header and footer that we used for the sizing. We want to also fix their width - * to what they currently are - */ - _fnApplyToChildren( function(nSizer, i) { - nSizer.innerHTML = ""; - nSizer.style.width = aApplied[i]; - //fix column align - nSizer.style.minWidth =nSizer.style.width; - }, anHeadSizers ); - - if ( o.nTFoot !== null ) - { - _fnApplyToChildren( function(nSizer, i) { - nSizer.innerHTML = ""; - nSizer.style.width = aAppliedFooter[i]; - }, anFootSizers ); - } - - /* Sanity check that the table is of a sensible width. If not then we are going to get - * misalignment - try to prevent this by not allowing the table to shrink below its min width - */ - if ( $(o.nTable).outerWidth() < iSanityWidth ) - { - /* The min width depends upon if we have a vertical scrollbar visible or not */ - var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || - $(nScrollBody).css('overflow-y') == "scroll")) ? - iSanityWidth+o.oScroll.iBarWidth : iSanityWidth; - - /* IE6/7 are a law unto themselves... */ - if ( ie67 && (nScrollBody.scrollHeight > - nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") ) - { - o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth ); - } - - /* Apply the calculated minimum width to the table wrappers */ - nScrollBody.style.width = _fnStringToCss( iCorrection ); - o.nScrollHead.style.width = _fnStringToCss( iCorrection ); - - if ( o.nTFoot !== null ) - { - o.nScrollFoot.style.width = _fnStringToCss( iCorrection ); - } - - /* And give the user a warning that we've stopped the table getting too small */ - if ( o.oScroll.sX === "" ) - { - _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+ - " misalignment. The table has been drawn at its minimum possible width." ); - } - else if ( o.oScroll.sXInner !== "" ) - { - _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+ - " misalignment. Increase the sScrollXInner value or remove it to allow automatic"+ - " calculation" ); - } - } - else - { - nScrollBody.style.width = _fnStringToCss( '100%' ); - o.nScrollHead.style.width = _fnStringToCss( '100%' ); - - if ( o.nTFoot !== null ) - { - o.nScrollFoot.style.width = _fnStringToCss( '100%' ); - } - } - - - /* - * 4. Clean up - */ - if ( o.oScroll.sY === "" ) - { - /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting - * the scrollbar height from the visible display, rather than adding it on. We need to - * set the height in order to sort this. Don't want to do it in any other browsers. - */ - if ( ie67 ) - { - nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth ); - } - } - - if ( o.oScroll.sY !== "" && o.oScroll.bCollapse ) - { - nScrollBody.style.height = _fnStringToCss( o.oScroll.sY ); - - var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ? - o.oScroll.iBarWidth : 0; - if ( o.nTable.offsetHeight < nScrollBody.offsetHeight ) - { - nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra ); - } - } - - /* Finally set the width's of the header and footer tables */ - var iOuterWidth = $(o.nTable).outerWidth(); - nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth ); - nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth ); - - // Figure out if there are scrollbar present - if so then we need a the header and footer to - // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) - var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll"; - nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; - - if ( o.nTFoot !== null ) - { - nScrollFootTable.style.width = _fnStringToCss( iOuterWidth ); - nScrollFootInner.style.width = _fnStringToCss( iOuterWidth ); - nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; - } - - /* Adjust the position of the header in case we loose the y-scrollbar */ - $(nScrollBody).scroll(); - - /* If sorting or filtering has occurred, jump the scrolling back to the top */ - if ( o.bSorted || o.bFiltered ) - { - nScrollBody.scrollTop = 0; - } - } - - - /** - * Apply a given function to the display child nodes of an element array (typically - * TD children of TR rows - * @param {function} fn Method to apply to the objects - * @param array {nodes} an1 List of elements to look through for display children - * @param array {nodes} an2 Another list (identical structure to the first) - optional - * @memberof DataTable#oApi - */ - function _fnApplyToChildren( fn, an1, an2 ) - { - var index=0, i=0, iLen=an1.length; - var nNode1, nNode2; - - while ( i < iLen ) - { - nNode1 = an1[i].firstChild; - nNode2 = an2 ? an2[i].firstChild : null; - while ( nNode1 ) - { - if ( nNode1.nodeType === 1 ) - { - if ( an2 ) - { - fn( nNode1, nNode2, index ); - } - else - { - fn( nNode1, index ); - } - index++; - } - nNode1 = nNode1.nextSibling; - nNode2 = an2 ? nNode2.nextSibling : null; - } - i++; - } - } - - /** - * Convert a CSS unit width to pixels (e.g. 2em) - * @param {string} sWidth width to be converted - * @param {node} nParent parent to get the with for (required for relative widths) - optional - * @returns {int} iWidth width in pixels - * @memberof DataTable#oApi - */ - function _fnConvertToWidth ( sWidth, nParent ) - { - if ( !sWidth || sWidth === null || sWidth === '' ) - { - return 0; - } - - if ( !nParent ) - { - nParent = document.body; - } - - var iWidth; - var nTmp = document.createElement( "div" ); - nTmp.style.width = _fnStringToCss( sWidth ); - - nParent.appendChild( nTmp ); - iWidth = nTmp.offsetWidth; - nParent.removeChild( nTmp ); - - return ( iWidth ); - } - - - /** - * Calculate the width of columns for the table - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnCalculateColumnWidths ( oSettings ) - { - var iTableWidth = oSettings.nTable.offsetWidth; - var iUserInputs = 0; - var iTmpWidth; - var iVisibleColumns = 0; - var iColums = oSettings.aoColumns.length; - var i, iIndex, iCorrector, iWidth; - var oHeaders = $('th', oSettings.nTHead); - var widthAttr = oSettings.nTable.getAttribute('width'); - var nWrapper = oSettings.nTable.parentNode; - - /* Convert any user input sizes into pixel sizes */ - for ( i=0 ; itd', nCalcTmp); - } - - /* Apply custom sizing to the cloned header */ - var nThs = _fnGetUniqueThs( oSettings, nTheadClone ); - iCorrector = 0; - for ( i=0 ; i 0 ) - { - oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth ); - } - iCorrector++; - } - } - - var cssWidth = $(nCalcTmp).css('width'); - oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ? - cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() ); - nCalcTmp.parentNode.removeChild( nCalcTmp ); - } - - if ( widthAttr ) - { - oSettings.nTable.style.width = _fnStringToCss( widthAttr ); - } - } - - - /** - * Adjust a table's width to take account of scrolling - * @param {object} oSettings dataTables settings object - * @param {node} n table node - * @memberof DataTable#oApi - */ - function _fnScrollingWidthAdjust ( oSettings, n ) - { - if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" ) - { - /* When y-scrolling only, we want to remove the width of the scroll bar so the table - * + scroll bar will fit into the area avaialble. - */ - var iOrigWidth = $(n).width(); - n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth ); - } - else if ( oSettings.oScroll.sX !== "" ) - { - /* When x-scrolling both ways, fix the table at it's current size, without adjusting */ - n.style.width = _fnStringToCss( $(n).outerWidth() ); - } - } - - - /** - * Get the widest node - * @param {object} oSettings dataTables settings object - * @param {int} iCol column of interest - * @returns {node} widest table node - * @memberof DataTable#oApi - */ - function _fnGetWidestNode( oSettings, iCol ) - { - var iMaxIndex = _fnGetMaxLenString( oSettings, iCol ); - if ( iMaxIndex < 0 ) - { - return null; - } - - if ( oSettings.aoData[iMaxIndex].nTr === null ) - { - var n = document.createElement('td'); - n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' ); - return n; - } - return _fnGetTdNodes(oSettings, iMaxIndex)[iCol]; - } - - - /** - * Get the maximum strlen for each data column - * @param {object} oSettings dataTables settings object - * @param {int} iCol column of interest - * @returns {string} max string length for each column - * @memberof DataTable#oApi - */ - function _fnGetMaxLenString( oSettings, iCol ) - { - var iMax = -1; - var iMaxIndex = -1; - - for ( var i=0 ; i/g, "" ); - if ( s.length > iMax ) - { - iMax = s.length; - iMaxIndex = i; - } - } - - return iMaxIndex; - } - - - /** - * Append a CSS unit (only if required) to a string - * @param {array} aArray1 first array - * @param {array} aArray2 second array - * @returns {int} 0 if match, 1 if length is different, 2 if no match - * @memberof DataTable#oApi - */ - function _fnStringToCss( s ) - { - if ( s === null ) - { - return "0px"; - } - - if ( typeof s == 'number' ) - { - if ( s < 0 ) - { - return "0px"; - } - return s+"px"; - } - - /* Check if the last character is not 0-9 */ - var c = s.charCodeAt( s.length-1 ); - if (c < 0x30 || c > 0x39) - { - return s; - } - return s+"px"; - } - - - /** - * Get the width of a scroll bar in this browser being used - * @returns {int} width in pixels - * @memberof DataTable#oApi - */ - function _fnScrollBarWidth () - { - var inner = document.createElement('p'); - var style = inner.style; - style.width = "100%"; - style.height = "200px"; - style.padding = "0px"; - - var outer = document.createElement('div'); - style = outer.style; - style.position = "absolute"; - style.top = "0px"; - style.left = "0px"; - style.visibility = "hidden"; - style.width = "200px"; - style.height = "150px"; - style.padding = "0px"; - style.overflow = "hidden"; - outer.appendChild(inner); - - document.body.appendChild(outer); - var w1 = inner.offsetWidth; - outer.style.overflow = 'scroll'; - var w2 = inner.offsetWidth; - if ( w1 == w2 ) - { - w2 = outer.clientWidth; - } - - document.body.removeChild(outer); - return (w1 - w2); - } - - /** - * Change the order of the table - * @param {object} oSettings dataTables settings object - * @param {bool} bApplyClasses optional - should we apply classes or not - * @memberof DataTable#oApi - */ - function _fnSort ( oSettings, bApplyClasses ) - { - var - i, iLen, j, jLen, k, kLen, - sDataType, nTh, - aaSort = [], - aiOrig = [], - oSort = DataTable.ext.oSort, - aoData = oSettings.aoData, - aoColumns = oSettings.aoColumns, - oAria = oSettings.oLanguage.oAria; - - /* No sorting required if server-side or no sorting array */ - if ( !oSettings.oFeatures.bServerSide && - (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) ) - { - aaSort = ( oSettings.aaSortingFixed !== null ) ? - oSettings.aaSortingFixed.concat( oSettings.aaSorting ) : - oSettings.aaSorting.slice(); - - /* If there is a sorting data type, and a function belonging to it, then we need to - * get the data from the developer's function and apply it for this column - */ - for ( i=0 ; i/g, "" ); - nTh = aoColumns[i].nTh; - nTh.removeAttribute('aria-sort'); - nTh.removeAttribute('aria-label'); - - /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ - if ( aoColumns[i].bSortable ) - { - if ( aaSort.length > 0 && aaSort[0][0] == i ) - { - nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" ); - - var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ? - aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0]; - nTh.setAttribute('aria-label', sTitle+ - (nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) ); - } - else - { - nTh.setAttribute('aria-label', sTitle+ - (aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) ); - } - } - else - { - nTh.setAttribute('aria-label', sTitle); - } - } - - /* Tell the draw function that we have sorted the data */ - oSettings.bSorted = true; - $(oSettings.oInstance).trigger('sort', oSettings); - - /* Copy the master data into the draw array and re-draw */ - if ( oSettings.oFeatures.bFilter ) - { - /* _fnFilter() will redraw the table for us */ - _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 ); - } - else - { - oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); - oSettings._iDisplayStart = 0; /* reset display back to page 0 */ - _fnCalculateEnd( oSettings ); - _fnDraw( oSettings ); - } - } - - - /** - * Attach a sort handler (click) to a node - * @param {object} oSettings dataTables settings object - * @param {node} nNode node to attach the handler to - * @param {int} iDataIndex column sorting index - * @param {function} [fnCallback] callback function - * @memberof DataTable#oApi - */ - function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback ) - { - _fnBindAction( nNode, {}, function (e) { - /* If the column is not sortable - don't to anything */ - if ( oSettings.aoColumns[iDataIndex].bSortable === false ) - { - return; - } - - /* - * This is a little bit odd I admit... I declare a temporary function inside the scope of - * _fnBuildHead and the click handler in order that the code presented here can be used - * twice - once for when bProcessing is enabled, and another time for when it is - * disabled, as we need to perform slightly different actions. - * Basically the issue here is that the Javascript engine in modern browsers don't - * appear to allow the rendering engine to update the display while it is still executing - * it's thread (well - it does but only after long intervals). This means that the - * 'processing' display doesn't appear for a table sort. To break the js thread up a bit - * I force an execution break by using setTimeout - but this breaks the expected - * thread continuation for the end-developer's point of view (their code would execute - * too early), so we only do it when we absolutely have to. - */ - var fnInnerSorting = function () { - var iColumn, iNextSort; - - /* If the shift key is pressed then we are multiple column sorting */ - if ( e.shiftKey ) - { - /* Are we already doing some kind of sort on this column? */ - var bFound = false; - for ( var i=0 ; i 0 && sCurrentClass.indexOf(sNewClass) == -1 ) - { - /* We need to add a class */ - nTds[i].className = sCurrentClass + " " + sNewClass; - } - } - } - } - - - - /** - * Save the state of a table in a cookie such that the page can be reloaded - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnSaveState ( oSettings ) - { - if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying ) - { - return; - } - - /* Store the interesting variables */ - var i, iLen, bInfinite=oSettings.oScroll.bInfinite; - var oState = { - "iCreate": new Date().getTime(), - "iStart": (bInfinite ? 0 : oSettings._iDisplayStart), - "iEnd": (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd), - "iLength": oSettings._iDisplayLength, - "aaSorting": $.extend( true, [], oSettings.aaSorting ), - "oSearch": $.extend( true, {}, oSettings.oPreviousSearch ), - "aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ), - "abVisCols": [] - }; - - for ( i=0, iLen=oSettings.aoColumns.length ; i 4096 ) /* Magic 10 for padding */ - { - for ( var i=0, iLen=aCookies.length ; i 4096 ) { - if ( aOldCookies.length === 0 ) { - // Deleted all DT cookies and still not enough space. Can't state save - return; - } - - var old = aOldCookies.pop(); - document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+ - aParts.join('/') + "/"; - } - } - - document.cookie = sFullCookie; - } - - - /** - * Read an old cookie to get a cookie with an old table state - * @param {string} sName name of the cookie to read - * @returns {string} contents of the cookie - or null if no cookie with that name found - * @memberof DataTable#oApi - */ - function _fnReadCookie ( sName ) - { - var - aParts = window.location.pathname.split('/'), - sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=', - sCookieContents = document.cookie.split(';'); - - for( var i=0 ; i=0 ; i-- ) - { - aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) ); - } - - if ( sTrigger !== null ) - { - $(oSettings.oInstance).trigger(sTrigger, aArgs); - } - - return aRet; - } - - - /** - * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other - * library, then we use that as it is fast, safe and accurate. If the function isn't - * available then we need to built it ourselves - the inspiration for this function comes - * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is - * not perfect and absolutely should not be used as a replacement to json2.js - but it does - * do what we need, without requiring a dependency for DataTables. - * @param {object} o JSON object to be converted - * @returns {string} JSON string - * @memberof DataTable#oApi - */ - var _fnJsonString = (window.JSON) ? JSON.stringify : function( o ) - { - /* Not an object or array */ - var sType = typeof o; - if (sType !== "object" || o === null) - { - // simple data type - if (sType === "string") - { - o = '"'+o+'"'; - } - return o+""; - } - - /* If object or array, need to recurse over it */ - var - sProp, mValue, - json = [], - bArr = $.isArray(o); - - for (sProp in o) - { - mValue = o[sProp]; - sType = typeof mValue; - - if (sType === "string") - { - mValue = '"'+mValue+'"'; - } - else if (sType === "object" && mValue !== null) - { - mValue = _fnJsonString(mValue); - } - - json.push((bArr ? "" : '"'+sProp+'":') + mValue); - } - - return (bArr ? "[" : "{") + json + (bArr ? "]" : "}"); - }; - - - /** - * From some browsers (specifically IE6/7) we need special handling to work around browser - * bugs - this function is used to detect when these workarounds are needed. - * @param {object} oSettings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnBrowserDetect( oSettings ) - { - /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the - * width of the scrollbar, while other browsers ensure the inner element is contained - * without forcing scrolling - */ - var n = $( - '
    '+ - '
    '+ - '
    '+ - '
    '+ - '
    ')[0]; - - document.body.appendChild( n ); - oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false; - document.body.removeChild( n ); - } - - - /** - * Perform a jQuery selector action on the table's TR elements (from the tbody) and - * return the resulting jQuery object. - * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on - * @param {object} [oOpts] Optional parameters for modifying the rows to be included - * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter - * criterion ("applied") or all TR elements (i.e. no filter). - * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. - * Can be either 'current', whereby the current sorting of the table is used, or - * 'original' whereby the original order the data was read into the table is used. - * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page - * ("current") or not ("all"). If 'current' is given, then order is assumed to be - * 'current' and filter is 'applied', regardless of what they might be given as. - * @returns {object} jQuery object, filtered by the given selector. - * @dtopt API - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Highlight every second row - * oTable.$('tr:odd').css('backgroundColor', 'blue'); - * } ); - * - * @example - * $(document).ready(function() { - * var oTable = $('#example').dataTable(); - * - * // Filter to rows with 'Webkit' in them, add a background colour and then - * // remove the filter, thus highlighting the 'Webkit' rows only. - * oTable.fnFilter('Webkit'); - * oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue'); - * oTable.fnFilter(''); - * } ); - */ - this.$ = function ( sSelector, oOpts ) - { - var i, iLen, a = [], tr; - var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); - var aoData = oSettings.aoData; - var aiDisplay = oSettings.aiDisplay; - var aiDisplayMaster = oSettings.aiDisplayMaster; - - if ( !oOpts ) - { - oOpts = {}; - } - - oOpts = $.extend( {}, { - "filter": "none", // applied - "order": "current", // "original" - "page": "all" // current - }, oOpts ); - - // Current page implies that order=current and fitler=applied, since it is fairly - // senseless otherwise - if ( oOpts.page == 'current' ) - { - for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i - *
  • 1D array of data - add a single row with the data provided
  • - *
  • 2D array of arrays - add multiple rows in a single call
  • - *
  • object - data object when using mData
  • - *
  • array of objects - multiple data objects when using mData
  • - * - * @param {bool} [bRedraw=true] redraw the table or not - * @returns {array} An array of integers, representing the list of indexes in - * aoData ({@link DataTable.models.oSettings}) that have been added to - * the table. - * @dtopt API - * - * @example - * // Global var for counter - * var giCount = 2; - * - * $(document).ready(function() { - * $('#example').dataTable(); - * } ); - * - * function fnClickAddRow() { - * $('#example').dataTable().fnAddData( [ - * giCount+".1", - * giCount+".2", - * giCount+".3", - * giCount+".4" ] - * ); - * - * giCount++; - * } - */ - this.fnAddData = function( mData, bRedraw ) - { - if ( mData.length === 0 ) - { - return []; - } - - var aiReturn = []; - var iTest; - - /* Find settings from table node */ - var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); - - /* Check if we want to add multiple rows or not */ - if ( typeof mData[0] === "object" && mData[0] !== null ) - { - for ( var i=0 ; i= oSettings.fnRecordsDisplay() ) - { - oSettings._iDisplayStart -= oSettings._iDisplayLength; - if ( oSettings._iDisplayStart < 0 ) - { - oSettings._iDisplayStart = 0; - } - } - - if ( bRedraw === undefined || bRedraw ) - { - _fnCalculateEnd( oSettings ); - _fnDraw( oSettings ); - } - - return oData; - }; - - - /** - * Restore the table to it's original state in the DOM by removing all of DataTables - * enhancements, alterations to the DOM structure of the table and event listeners. - * @param {boolean} [bRemove=false] Completely remove the table from the DOM - * @dtopt API - * - * @example - * $(document).ready(function() { - * // This example is fairly pointless in reality, but shows how fnDestroy can be used - * var oTable = $('#example').dataTable(); - * oTable.fnDestroy(); - * } ); - */ - this.fnDestroy = function ( bRemove ) - { - var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); - var nOrig = oSettings.nTableWrapper.parentNode; - var nBody = oSettings.nTBody; - var i, iLen; - - bRemove = (bRemove===undefined) ? false : bRemove; - - /* Flag to note that the table is currently being destroyed - no action should be taken */ - oSettings.bDestroying = true; - - /* Fire off the destroy callbacks for plug-ins etc */ - _fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] ); - - /* If the table is not being removed, restore the hidden columns */ - if ( !bRemove ) - { - for ( i=0, iLen=oSettings.aoColumns.length ; itr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove(); - - /* When scrolling we had to break the table up - restore it */ - if ( oSettings.nTable != oSettings.nTHead.parentNode ) - { - $(oSettings.nTable).children('thead').remove(); - oSettings.nTable.appendChild( oSettings.nTHead ); - } - - if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode ) - { - $(oSettings.nTable).children('tfoot').remove(); - oSettings.nTable.appendChild( oSettings.nTFoot ); - } - - /* Remove the DataTables generated nodes, events and classes */ - oSettings.nTable.parentNode.removeChild( oSettings.nTable ); - $(oSettings.nTableWrapper).remove(); - - oSettings.aaSorting = []; - oSettings.aaSortingFixed = []; - _fnSortingClasses( oSettings ); - - $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') ); - - $('th, td', oSettings.nTHead).removeClass( [ - oSettings.oClasses.sSortable, - oSettings.oClasses.sSortableAsc, - oSettings.oClasses.sSortableDesc, - oSettings.oClasses.sSortableNone ].join(' ') - ); - if ( oSettings.bJUI ) - { - $('th span.'+oSettings.oClasses.sSortIcon - + ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove(); - - $('th, td', oSettings.nTHead).each( function () { - var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this); - var kids = jqWrapper.contents(); - $(this).append( kids ); - jqWrapper.remove(); - } ); - } - - /* Add the TR elements back into the table in their original order */ - if ( !bRemove && oSettings.nTableReinsertBefore ) - { - nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore ); - } - else if ( !bRemove ) - { - nOrig.appendChild( oSettings.nTable ); - } - - for ( i=0, iLen=oSettings.aoData.length ; i
    ')[0]; + oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable ); + + /* + * All DataTables are wrapped in a div + */ + oSettings.nTableWrapper = $('
    ')[0]; + oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; + + /* Track where we want to insert the option */ + var nInsertNode = oSettings.nTableWrapper; + + /* Loop over the user set positioning and place the elements as needed */ + var aDom = oSettings.sDom.split(''); + var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j; + for ( var i=0 ; i
    ')[0]; + + /* Check to see if we should append an id and/or a class name to the container */ + cNext = aDom[i+1]; + if ( cNext == "'" || cNext == '"' ) + { + sAttr = ""; + j = 2; + while ( aDom[i+j] != cNext ) + { + sAttr += aDom[i+j]; + j++; + } + + /* Replace jQuery UI constants */ + if ( sAttr == "H" ) + { + sAttr = oSettings.oClasses.sJUIHeader; + } + else if ( sAttr == "F" ) + { + sAttr = oSettings.oClasses.sJUIFooter; + } + + /* The attribute can be in the format of "#id.class", "#id" or "class" This logic + * breaks the string into parts and applies them as needed + */ + if ( sAttr.indexOf('.') != -1 ) + { + var aSplit = sAttr.split('.'); + nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); + nNewNode.className = aSplit[1]; + } + else if ( sAttr.charAt(0) == "#" ) + { + nNewNode.id = sAttr.substr(1, sAttr.length-1); + } + else + { + nNewNode.className = sAttr; + } + + i += j; /* Move along the position array */ + } + + nInsertNode.appendChild( nNewNode ); + nInsertNode = nNewNode; + } + else if ( cOption == '>' ) + { + /* End container div */ + nInsertNode = nInsertNode.parentNode; + } + else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange ) + { + /* Length */ + nTmp = _fnFeatureHtmlLength( oSettings ); + iPushFeature = 1; + } + else if ( cOption == 'f' && oSettings.oFeatures.bFilter ) + { + /* Filter */ + nTmp = _fnFeatureHtmlFilter( oSettings ); + iPushFeature = 1; + } + else if ( cOption == 'r' && oSettings.oFeatures.bProcessing ) + { + /* pRocessing */ + nTmp = _fnFeatureHtmlProcessing( oSettings ); + iPushFeature = 1; + } + else if ( cOption == 't' ) + { + /* Table */ + nTmp = _fnFeatureHtmlTable( oSettings ); + iPushFeature = 1; + } + else if ( cOption == 'i' && oSettings.oFeatures.bInfo ) + { + /* Info */ + nTmp = _fnFeatureHtmlInfo( oSettings ); + iPushFeature = 1; + } + else if ( cOption == 'p' && oSettings.oFeatures.bPaginate ) + { + /* Pagination */ + nTmp = _fnFeatureHtmlPaginate( oSettings ); + iPushFeature = 1; + } + else if ( DataTable.ext.aoFeatures.length !== 0 ) + { + /* Plug-in features */ + var aoFeatures = DataTable.ext.aoFeatures; + for ( var k=0, kLen=aoFeatures.length ; k') : + sSearchStr==="" ? '' : sSearchStr+' '; + + var nFilter = document.createElement( 'div' ); + nFilter.className = oSettings.oClasses.sFilter; + nFilter.innerHTML = ''; + if ( !oSettings.aanFeatures.f ) + { + nFilter.id = oSettings.sTableId+'_filter'; + } + + var jqFilter = $('input[type="text"]', nFilter); + + // Store a reference to the input element, so other input elements could be + // added to the filter wrapper if needed (submit button for example) + nFilter._DT_Input = jqFilter[0]; + + jqFilter.val( oPreviousSearch.sSearch.replace('"','"') ); + jqFilter.bind( 'keyup.DT', function(e) { + /* Update all other filter input elements for the new display */ + var n = oSettings.aanFeatures.f; + var val = this.value==="" ? "" : this.value; // mental IE8 fix :-( + + for ( var i=0, iLen=n.length ; i=0 ; i-- ) + { + var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ), + oSettings.aoColumns[iColumn].sType ); + if ( ! rpSearch.test( sData ) ) + { + oSettings.aiDisplay.splice( i, 1 ); + iIndexCorrector++; + } + } + } + + + /** + * Filter the data table based on user input and draw the table + * @param {object} oSettings dataTables settings object + * @param {string} sInput string to filter on + * @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0) + * @param {bool} bRegex treat as a regular expression or not + * @param {bool} bSmart perform smart filtering or not + * @param {bool} bCaseInsensitive Do case insenstive matching or not + * @memberof DataTable#oApi + */ + function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive ) + { + var i; + var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive ); + var oPrevSearch = oSettings.oPreviousSearch; + + /* Check if we are forcing or not - optional parameter */ + if ( !iForce ) + { + iForce = 0; + } + + /* Need to take account of custom filtering functions - always filter */ + if ( DataTable.ext.afnFiltering.length !== 0 ) + { + iForce = 1; + } + + /* + * If the input is blank - we want the full data set + */ + if ( sInput.length <= 0 ) + { + oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length); + oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); + } + else + { + /* + * We are starting a new search or the new search string is smaller + * then the old one (i.e. delete). Search from the master array + */ + if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length || + oPrevSearch.sSearch.length > sInput.length || iForce == 1 || + sInput.indexOf(oPrevSearch.sSearch) !== 0 ) + { + /* Nuke the old display array - we are going to rebuild it */ + oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length); + + /* Force a rebuild of the search array */ + _fnBuildSearchArray( oSettings, 1 ); + + /* Search through all records to populate the search array + * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 + * mapping + */ + for ( i=0 ; i').html(sSearch).text(); + } + + // Strip newline characters + return sSearch.replace( /[\n\r]/g, " " ); + } + + /** + * Build a regular expression object suitable for searching a table + * @param {string} sSearch string to search for + * @param {bool} bRegex treat as a regular expression or not + * @param {bool} bSmart perform smart filtering or not + * @param {bool} bCaseInsensitive Do case insensitive matching or not + * @returns {RegExp} constructed object + * @memberof DataTable#oApi + */ + function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive ) + { + var asSearch, sRegExpString; + + if ( bSmart ) + { + /* Generate the regular expression to use. Something along the lines of: + * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$ + */ + asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' ); + sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$'; + return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" ); + } + else + { + sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch ); + return new RegExp( sSearch, bCaseInsensitive ? "i" : "" ); + } + } + + + /** + * Convert raw data into something that the user can search on + * @param {string} sData data to be modified + * @param {string} sType data type + * @returns {string} search string + * @memberof DataTable#oApi + */ + function _fnDataToSearch ( sData, sType ) + { + if ( typeof DataTable.ext.ofnSearch[sType] === "function" ) + { + return DataTable.ext.ofnSearch[sType]( sData ); + } + else if ( sData === null ) + { + return ''; + } + else if ( sType == "html" ) + { + return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" ); + } + else if ( typeof sData === "string" ) + { + return sData.replace(/[\r\n]/g," "); + } + return sData; + } + + + /** + * scape a string such that it can be used in a regular expression + * @param {string} sVal string to escape + * @returns {string} escaped string + * @memberof DataTable#oApi + */ + function _fnEscapeRegex ( sVal ) + { + var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ]; + var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' ); + return sVal.replace(reReplace, '\\$1'); + } + + + /** + * Generate the node required for the info display + * @param {object} oSettings dataTables settings object + * @returns {node} Information element + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlInfo ( oSettings ) + { + var nInfo = document.createElement( 'div' ); + nInfo.className = oSettings.oClasses.sInfo; + + /* Actions that are to be taken once only for this feature */ + if ( !oSettings.aanFeatures.i ) + { + /* Add draw callback */ + oSettings.aoDrawCallback.push( { + "fn": _fnUpdateInfo, + "sName": "information" + } ); + + /* Add id */ + nInfo.id = oSettings.sTableId+'_info'; + } + oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' ); + + return nInfo; + } + + + /** + * Update the information elements in the display + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnUpdateInfo ( oSettings ) + { + /* Show information about the table */ + if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 ) + { + return; + } + + var + oLang = oSettings.oLanguage, + iStart = oSettings._iDisplayStart+1, + iEnd = oSettings.fnDisplayEnd(), + iMax = oSettings.fnRecordsTotal(), + iTotal = oSettings.fnRecordsDisplay(), + sOut; + + if ( iTotal === 0 ) + { + /* Empty record set */ + sOut = oLang.sInfoEmpty; + } + else { + /* Normal record set */ + sOut = oLang.sInfo; + } + + if ( iTotal != iMax ) + { + /* Record set after filtering */ + sOut += ' ' + oLang.sInfoFiltered; + } + + // Convert the macros + sOut += oLang.sInfoPostFix; + sOut = _fnInfoMacros( oSettings, sOut ); + + if ( oLang.fnInfoCallback !== null ) + { + sOut = oLang.fnInfoCallback.call( oSettings.oInstance, + oSettings, iStart, iEnd, iMax, iTotal, sOut ); + } + + var n = oSettings.aanFeatures.i; + for ( var i=0, iLen=n.length ; i'; + var i, iLen; + var aLengthMenu = oSettings.aLengthMenu; + + if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' && + typeof aLengthMenu[1] === 'object' ) + { + for ( i=0, iLen=aLengthMenu[0].length ; i'+aLengthMenu[1][i]+''; + } + } + else + { + for ( i=0, iLen=aLengthMenu.length ; i'+aLengthMenu[i]+''; + } + } + sStdMenu += ''; + + var nLength = document.createElement( 'div' ); + if ( !oSettings.aanFeatures.l ) + { + nLength.id = oSettings.sTableId+'_length'; + } + nLength.className = oSettings.oClasses.sLength; + nLength.innerHTML = ''; + + /* + * Set the length to the current display length - thanks to Andrea Pavlovic for this fix, + * and Stefan Skopnik for fixing the fix! + */ + $('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true); + + $('select', nLength).bind( 'change.DT', function(e) { + var iVal = $(this).val(); + + /* Update all other length options for the new display */ + var n = oSettings.aanFeatures.l; + for ( i=0, iLen=n.length ; i oSettings.aiDisplay.length || + oSettings._iDisplayLength == -1 ) + { + oSettings._iDisplayEnd = oSettings.aiDisplay.length; + } + else + { + oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength; + } + } + } + + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Note that most of the paging logic is done in + * DataTable.ext.oPagination + */ + + /** + * Generate the node required for default pagination + * @param {object} oSettings dataTables settings object + * @returns {node} Pagination feature node + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlPaginate ( oSettings ) + { + if ( oSettings.oScroll.bInfinite ) + { + return null; + } + + var nPaginate = document.createElement( 'div' ); + nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType; + + DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, + function( oSettings ) { + _fnCalculateEnd( oSettings ); + _fnDraw( oSettings ); + } + ); + + /* Add a draw callback for the pagination on first instance, to update the paging display */ + if ( !oSettings.aanFeatures.p ) + { + oSettings.aoDrawCallback.push( { + "fn": function( oSettings ) { + DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) { + _fnCalculateEnd( oSettings ); + _fnDraw( oSettings ); + } ); + }, + "sName": "pagination" + } ); + } + return nPaginate; + } + + + /** + * Alter the display settings to change the page + * @param {object} oSettings dataTables settings object + * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" + * or page number to jump to (integer) + * @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1 + * @memberof DataTable#oApi + */ + function _fnPageChange ( oSettings, mAction ) + { + var iOldStart = oSettings._iDisplayStart; + + if ( typeof mAction === "number" ) + { + oSettings._iDisplayStart = mAction * oSettings._iDisplayLength; + if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() ) + { + oSettings._iDisplayStart = 0; + } + } + else if ( mAction == "first" ) + { + oSettings._iDisplayStart = 0; + } + else if ( mAction == "previous" ) + { + oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ? + oSettings._iDisplayStart - oSettings._iDisplayLength : + 0; + + /* Correct for under-run */ + if ( oSettings._iDisplayStart < 0 ) + { + oSettings._iDisplayStart = 0; + } + } + else if ( mAction == "next" ) + { + if ( oSettings._iDisplayLength >= 0 ) + { + /* Make sure we are not over running the display array */ + if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() ) + { + oSettings._iDisplayStart += oSettings._iDisplayLength; + } + } + else + { + oSettings._iDisplayStart = 0; + } + } + else if ( mAction == "last" ) + { + if ( oSettings._iDisplayLength >= 0 ) + { + var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1; + oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength; + } + else + { + oSettings._iDisplayStart = 0; + } + } + else + { + _fnLog( oSettings, 0, "Unknown paging action: "+mAction ); + } + $(oSettings.oInstance).trigger('page', oSettings); + + return iOldStart != oSettings._iDisplayStart; + } + + + + /** + * Generate the node required for the processing node + * @param {object} oSettings dataTables settings object + * @returns {node} Processing element + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlProcessing ( oSettings ) + { + var nProcessing = document.createElement( 'div' ); + + if ( !oSettings.aanFeatures.r ) + { + nProcessing.id = oSettings.sTableId+'_processing'; + } + nProcessing.innerHTML = oSettings.oLanguage.sProcessing; + nProcessing.className = oSettings.oClasses.sProcessing; + oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable ); + + return nProcessing; + } + + + /** + * Display or hide the processing indicator + * @param {object} oSettings dataTables settings object + * @param {bool} bShow Show the processing indicator (true) or not (false) + * @memberof DataTable#oApi + */ + function _fnProcessingDisplay ( oSettings, bShow ) + { + if ( oSettings.oFeatures.bProcessing ) + { + var an = oSettings.aanFeatures.r; + for ( var i=0, iLen=an.length ; i 0 ) + { + nCaption = nCaption[0]; + if ( nCaption._captionSide === "top" ) + { + nScrollHeadTable.appendChild( nCaption ); + } + else if ( nCaption._captionSide === "bottom" && nTfoot ) + { + nScrollFootTable.appendChild( nCaption ); + } + } + + /* + * Sizing + */ + /* When x-scrolling add the width and a scroller to move the header with the body */ + if ( oSettings.oScroll.sX !== "" ) + { + nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX ); + nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX ); + + if ( nTfoot !== null ) + { + nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX ); + } + + /* When the body is scrolled, then we also want to scroll the headers */ + $(nScrollBody).scroll( function (e) { + nScrollHead.scrollLeft = this.scrollLeft; + + if ( nTfoot !== null ) + { + nScrollFoot.scrollLeft = this.scrollLeft; + } + } ); + } + + /* When yscrolling, add the height */ + if ( oSettings.oScroll.sY !== "" ) + { + nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY ); + } + + /* Redraw - align columns across the tables */ + oSettings.aoDrawCallback.push( { + "fn": _fnScrollDraw, + "sName": "scrolling" + } ); + + /* Infinite scrolling event handlers */ + if ( oSettings.oScroll.bInfinite ) + { + $(nScrollBody).scroll( function() { + /* Use a blocker to stop scrolling from loading more data while other data is still loading */ + if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 ) + { + /* Check if we should load the next data set */ + if ( $(this).scrollTop() + $(this).height() > + $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap ) + { + /* Only do the redraw if we have to - we might be at the end of the data */ + if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() ) + { + _fnPageChange( oSettings, 'next' ); + _fnCalculateEnd( oSettings ); + _fnDraw( oSettings ); + } + } + } + } ); + } + + oSettings.nScrollHead = nScrollHead; + oSettings.nScrollFoot = nScrollFoot; + + return nScroller; + } + + + /** + * Update the various tables for resizing. It's a bit of a pig this function, but + * basically the idea to: + * 1. Re-create the table inside the scrolling div + * 2. Take live measurements from the DOM + * 3. Apply the measurements + * 4. Clean up + * @param {object} o dataTables settings object + * @returns {node} Node to add to the DOM + * @memberof DataTable#oApi + */ + function _fnScrollDraw ( o ) + { + var + nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0], + nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0], + nScrollBody = o.nTable.parentNode, + i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis, + nTheadSize, nTfootSize, + iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth, + nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null, + nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null, + ie67 = o.oBrowser.bScrollOversize, + zeroOut = function(nSizer) { + oStyle = nSizer.style; + oStyle.paddingTop = "0"; + oStyle.paddingBottom = "0"; + oStyle.borderTopWidth = "0"; + oStyle.borderBottomWidth = "0"; + oStyle.height = 0; + }; + + /* + * 1. Re-create the table inside the scrolling div + */ + + /* Remove the old minimised thead and tfoot elements in the inner table */ + $(o.nTable).children('thead, tfoot').remove(); + + /* Clone the current header and footer elements and then place it into the inner table */ + nTheadSize = $(o.nTHead).clone()[0]; + o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] ); + anHeadToSize = o.nTHead.getElementsByTagName('tr'); + anHeadSizers = nTheadSize.getElementsByTagName('tr'); + + if ( o.nTFoot !== null ) + { + nTfootSize = $(o.nTFoot).clone()[0]; + o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] ); + anFootToSize = o.nTFoot.getElementsByTagName('tr'); + anFootSizers = nTfootSize.getElementsByTagName('tr'); + } + + /* + * 2. Take live measurements from the DOM - do not alter the DOM itself! + */ + + /* Remove old sizing and apply the calculated column widths + * Get the unique column headers in the newly created (cloned) header. We want to apply the + * calculated sizes to this header + */ + if ( o.oScroll.sX === "" ) + { + nScrollBody.style.width = '100%'; + nScrollHeadInner.parentNode.style.width = '100%'; + } + + var nThs = _fnGetUniqueThs( o, nTheadSize ); + for ( i=0, iLen=nThs.length ; i nScrollBody.offsetHeight || + $(nScrollBody).css('overflow-y') == "scroll") ) + { + o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth); + } + } + else + { + if ( o.oScroll.sXInner !== "" ) + { + /* x scroll inner has been given - use it */ + o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner); + } + else if ( iSanityWidth == $(nScrollBody).width() && + $(nScrollBody).height() < $(o.nTable).height() ) + { + /* There is y-scrolling - try to take account of the y scroll bar */ + o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth ); + if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth ) + { + /* Not possible to take account of it */ + o.nTable.style.width = _fnStringToCss( iSanityWidth ); + } + } + else + { + /* All else fails */ + o.nTable.style.width = _fnStringToCss( iSanityWidth ); + } + } + + /* Recalculate the sanity width - now that we've applied the required width, before it was + * a temporary variable. This is required because the column width calculation is done + * before this table DOM is created. + */ + iSanityWidth = $(o.nTable).outerWidth(); + + /* We want the hidden header to have zero height, so remove padding and borders. Then + * set the width based on the real headers + */ + + // Apply all styles in one pass. Invalidates layout only once because we don't read any + // DOM properties. + _fnApplyToChildren( zeroOut, anHeadSizers ); + + // Read all widths in next pass. Forces layout only once because we do not change + // any DOM properties. + _fnApplyToChildren( function(nSizer) { + aApplied.push( _fnStringToCss( $(nSizer).width() ) ); + }, anHeadSizers ); + + // Apply all widths in final pass. Invalidates layout only once because we do not + // read any DOM properties. + _fnApplyToChildren( function(nToSize, i) { + nToSize.style.width = aApplied[i]; + }, anHeadToSize ); + + $(anHeadSizers).height(0); + + /* Same again with the footer if we have one */ + if ( o.nTFoot !== null ) + { + _fnApplyToChildren( zeroOut, anFootSizers ); + + _fnApplyToChildren( function(nSizer) { + aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) ); + }, anFootSizers ); + + _fnApplyToChildren( function(nToSize, i) { + nToSize.style.width = aAppliedFooter[i]; + }, anFootToSize ); + + $(anFootSizers).height(0); + } + + /* + * 3. Apply the measurements + */ + + /* "Hide" the header and footer that we used for the sizing. We want to also fix their width + * to what they currently are + */ + _fnApplyToChildren( function(nSizer, i) { + nSizer.innerHTML = ""; + nSizer.style.width = aApplied[i]; + //fix column align + nSizer.style.minWidth =nSizer.style.width; + }, anHeadSizers ); + + if ( o.nTFoot !== null ) + { + _fnApplyToChildren( function(nSizer, i) { + nSizer.innerHTML = ""; + nSizer.style.width = aAppliedFooter[i]; + }, anFootSizers ); + } + + /* Sanity check that the table is of a sensible width. If not then we are going to get + * misalignment - try to prevent this by not allowing the table to shrink below its min width + */ + if ( $(o.nTable).outerWidth() < iSanityWidth ) + { + /* The min width depends upon if we have a vertical scrollbar visible or not */ + var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || + $(nScrollBody).css('overflow-y') == "scroll")) ? + iSanityWidth+o.oScroll.iBarWidth : iSanityWidth; + + /* IE6/7 are a law unto themselves... */ + if ( ie67 && (nScrollBody.scrollHeight > + nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") ) + { + o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth ); + } + + /* Apply the calculated minimum width to the table wrappers */ + nScrollBody.style.width = _fnStringToCss( iCorrection ); + o.nScrollHead.style.width = _fnStringToCss( iCorrection ); + + if ( o.nTFoot !== null ) + { + o.nScrollFoot.style.width = _fnStringToCss( iCorrection ); + } + + /* And give the user a warning that we've stopped the table getting too small */ + if ( o.oScroll.sX === "" ) + { + _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+ + " misalignment. The table has been drawn at its minimum possible width." ); + } + else if ( o.oScroll.sXInner !== "" ) + { + _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+ + " misalignment. Increase the sScrollXInner value or remove it to allow automatic"+ + " calculation" ); + } + } + else + { + nScrollBody.style.width = _fnStringToCss( '100%' ); + o.nScrollHead.style.width = _fnStringToCss( '100%' ); + + if ( o.nTFoot !== null ) + { + o.nScrollFoot.style.width = _fnStringToCss( '100%' ); + } + } + + + /* + * 4. Clean up + */ + if ( o.oScroll.sY === "" ) + { + /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting + * the scrollbar height from the visible display, rather than adding it on. We need to + * set the height in order to sort this. Don't want to do it in any other browsers. + */ + if ( ie67 ) + { + nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth ); + } + } + + if ( o.oScroll.sY !== "" && o.oScroll.bCollapse ) + { + nScrollBody.style.height = _fnStringToCss( o.oScroll.sY ); + + var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ? + o.oScroll.iBarWidth : 0; + if ( o.nTable.offsetHeight < nScrollBody.offsetHeight ) + { + nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra ); + } + } + + /* Finally set the width's of the header and footer tables */ + var iOuterWidth = $(o.nTable).outerWidth(); + nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth ); + nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth ); + + // Figure out if there are scrollbar present - if so then we need a the header and footer to + // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) + var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll"; + nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; + + if ( o.nTFoot !== null ) + { + nScrollFootTable.style.width = _fnStringToCss( iOuterWidth ); + nScrollFootInner.style.width = _fnStringToCss( iOuterWidth ); + nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; + } + + /* Adjust the position of the header in case we loose the y-scrollbar */ + $(nScrollBody).scroll(); + + /* If sorting or filtering has occurred, jump the scrolling back to the top */ + if ( o.bSorted || o.bFiltered ) + { + nScrollBody.scrollTop = 0; + } + } + + + /** + * Apply a given function to the display child nodes of an element array (typically + * TD children of TR rows + * @param {function} fn Method to apply to the objects + * @param array {nodes} an1 List of elements to look through for display children + * @param array {nodes} an2 Another list (identical structure to the first) - optional + * @memberof DataTable#oApi + */ + function _fnApplyToChildren( fn, an1, an2 ) + { + var index=0, i=0, iLen=an1.length; + var nNode1, nNode2; + + while ( i < iLen ) + { + nNode1 = an1[i].firstChild; + nNode2 = an2 ? an2[i].firstChild : null; + while ( nNode1 ) + { + if ( nNode1.nodeType === 1 ) + { + if ( an2 ) + { + fn( nNode1, nNode2, index ); + } + else + { + fn( nNode1, index ); + } + index++; + } + nNode1 = nNode1.nextSibling; + nNode2 = an2 ? nNode2.nextSibling : null; + } + i++; + } + } + + /** + * Convert a CSS unit width to pixels (e.g. 2em) + * @param {string} sWidth width to be converted + * @param {node} nParent parent to get the with for (required for relative widths) - optional + * @returns {int} iWidth width in pixels + * @memberof DataTable#oApi + */ + function _fnConvertToWidth ( sWidth, nParent ) + { + if ( !sWidth || sWidth === null || sWidth === '' ) + { + return 0; + } + + if ( !nParent ) + { + nParent = document.body; + } + + var iWidth; + var nTmp = document.createElement( "div" ); + nTmp.style.width = _fnStringToCss( sWidth ); + + nParent.appendChild( nTmp ); + iWidth = nTmp.offsetWidth; + nParent.removeChild( nTmp ); + + return ( iWidth ); + } + + + /** + * Calculate the width of columns for the table + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnCalculateColumnWidths ( oSettings ) + { + var iTableWidth = oSettings.nTable.offsetWidth; + var iUserInputs = 0; + var iTmpWidth; + var iVisibleColumns = 0; + var iColums = oSettings.aoColumns.length; + var i, iIndex, iCorrector, iWidth; + var oHeaders = $('th', oSettings.nTHead); + var widthAttr = oSettings.nTable.getAttribute('width'); + var nWrapper = oSettings.nTable.parentNode; + + /* Convert any user input sizes into pixel sizes */ + for ( i=0 ; itd', nCalcTmp); + } + + /* Apply custom sizing to the cloned header */ + var nThs = _fnGetUniqueThs( oSettings, nTheadClone ); + iCorrector = 0; + for ( i=0 ; i 0 ) + { + oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth ); + } + iCorrector++; + } + } + + var cssWidth = $(nCalcTmp).css('width'); + oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ? + cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() ); + nCalcTmp.parentNode.removeChild( nCalcTmp ); + } + + if ( widthAttr ) + { + oSettings.nTable.style.width = _fnStringToCss( widthAttr ); + } + } + + + /** + * Adjust a table's width to take account of scrolling + * @param {object} oSettings dataTables settings object + * @param {node} n table node + * @memberof DataTable#oApi + */ + function _fnScrollingWidthAdjust ( oSettings, n ) + { + if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" ) + { + /* When y-scrolling only, we want to remove the width of the scroll bar so the table + * + scroll bar will fit into the area avaialble. + */ + var iOrigWidth = $(n).width(); + n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth ); + } + else if ( oSettings.oScroll.sX !== "" ) + { + /* When x-scrolling both ways, fix the table at it's current size, without adjusting */ + n.style.width = _fnStringToCss( $(n).outerWidth() ); + } + } + + + /** + * Get the widest node + * @param {object} oSettings dataTables settings object + * @param {int} iCol column of interest + * @returns {node} widest table node + * @memberof DataTable#oApi + */ + function _fnGetWidestNode( oSettings, iCol ) + { + var iMaxIndex = _fnGetMaxLenString( oSettings, iCol ); + if ( iMaxIndex < 0 ) + { + return null; + } + + if ( oSettings.aoData[iMaxIndex].nTr === null ) + { + var n = document.createElement('td'); + n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' ); + return n; + } + return _fnGetTdNodes(oSettings, iMaxIndex)[iCol]; + } + + + /** + * Get the maximum strlen for each data column + * @param {object} oSettings dataTables settings object + * @param {int} iCol column of interest + * @returns {string} max string length for each column + * @memberof DataTable#oApi + */ + function _fnGetMaxLenString( oSettings, iCol ) + { + var iMax = -1; + var iMaxIndex = -1; + + for ( var i=0 ; i/g, "" ); + if ( s.length > iMax ) + { + iMax = s.length; + iMaxIndex = i; + } + } + + return iMaxIndex; + } + + + /** + * Append a CSS unit (only if required) to a string + * @param {array} aArray1 first array + * @param {array} aArray2 second array + * @returns {int} 0 if match, 1 if length is different, 2 if no match + * @memberof DataTable#oApi + */ + function _fnStringToCss( s ) + { + if ( s === null ) + { + return "0px"; + } + + if ( typeof s == 'number' ) + { + if ( s < 0 ) + { + return "0px"; + } + return s+"px"; + } + + /* Check if the last character is not 0-9 */ + var c = s.charCodeAt( s.length-1 ); + if (c < 0x30 || c > 0x39) + { + return s; + } + return s+"px"; + } + + + /** + * Get the width of a scroll bar in this browser being used + * @returns {int} width in pixels + * @memberof DataTable#oApi + */ + function _fnScrollBarWidth () + { + var inner = document.createElement('p'); + var style = inner.style; + style.width = "100%"; + style.height = "200px"; + style.padding = "0px"; + + var outer = document.createElement('div'); + style = outer.style; + style.position = "absolute"; + style.top = "0px"; + style.left = "0px"; + style.visibility = "hidden"; + style.width = "200px"; + style.height = "150px"; + style.padding = "0px"; + style.overflow = "hidden"; + outer.appendChild(inner); + + document.body.appendChild(outer); + var w1 = inner.offsetWidth; + outer.style.overflow = 'scroll'; + var w2 = inner.offsetWidth; + if ( w1 == w2 ) + { + w2 = outer.clientWidth; + } + + document.body.removeChild(outer); + return (w1 - w2); + } + + /** + * Change the order of the table + * @param {object} oSettings dataTables settings object + * @param {bool} bApplyClasses optional - should we apply classes or not + * @memberof DataTable#oApi + */ + function _fnSort ( oSettings, bApplyClasses ) + { + var + i, iLen, j, jLen, k, kLen, + sDataType, nTh, + aaSort = [], + aiOrig = [], + oSort = DataTable.ext.oSort, + aoData = oSettings.aoData, + aoColumns = oSettings.aoColumns, + oAria = oSettings.oLanguage.oAria; + + /* No sorting required if server-side or no sorting array */ + if ( !oSettings.oFeatures.bServerSide && + (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) ) + { + aaSort = ( oSettings.aaSortingFixed !== null ) ? + oSettings.aaSortingFixed.concat( oSettings.aaSorting ) : + oSettings.aaSorting.slice(); + + /* If there is a sorting data type, and a function belonging to it, then we need to + * get the data from the developer's function and apply it for this column + */ + for ( i=0 ; i/g, "" ); + nTh = aoColumns[i].nTh; + nTh.removeAttribute('aria-sort'); + nTh.removeAttribute('aria-label'); + + /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ + if ( aoColumns[i].bSortable ) + { + if ( aaSort.length > 0 && aaSort[0][0] == i ) + { + nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" ); + + var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ? + aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0]; + nTh.setAttribute('aria-label', sTitle+ + (nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) ); + } + else + { + nTh.setAttribute('aria-label', sTitle+ + (aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) ); + } + } + else + { + nTh.setAttribute('aria-label', sTitle); + } + } + + /* Tell the draw function that we have sorted the data */ + oSettings.bSorted = true; + $(oSettings.oInstance).trigger('sort', oSettings); + + /* Copy the master data into the draw array and re-draw */ + if ( oSettings.oFeatures.bFilter ) + { + /* _fnFilter() will redraw the table for us */ + _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 ); + } + else + { + oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); + oSettings._iDisplayStart = 0; /* reset display back to page 0 */ + _fnCalculateEnd( oSettings ); + _fnDraw( oSettings ); + } + } + + + /** + * Attach a sort handler (click) to a node + * @param {object} oSettings dataTables settings object + * @param {node} nNode node to attach the handler to + * @param {int} iDataIndex column sorting index + * @param {function} [fnCallback] callback function + * @memberof DataTable#oApi + */ + function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback ) + { + _fnBindAction( nNode, {}, function (e) { + /* If the column is not sortable - don't to anything */ + if ( oSettings.aoColumns[iDataIndex].bSortable === false ) + { + return; + } + + /* + * This is a little bit odd I admit... I declare a temporary function inside the scope of + * _fnBuildHead and the click handler in order that the code presented here can be used + * twice - once for when bProcessing is enabled, and another time for when it is + * disabled, as we need to perform slightly different actions. + * Basically the issue here is that the Javascript engine in modern browsers don't + * appear to allow the rendering engine to update the display while it is still executing + * it's thread (well - it does but only after long intervals). This means that the + * 'processing' display doesn't appear for a table sort. To break the js thread up a bit + * I force an execution break by using setTimeout - but this breaks the expected + * thread continuation for the end-developer's point of view (their code would execute + * too early), so we only do it when we absolutely have to. + */ + var fnInnerSorting = function () { + var iColumn, iNextSort; + + /* If the shift key is pressed then we are multiple column sorting */ + if ( e.shiftKey ) + { + /* Are we already doing some kind of sort on this column? */ + var bFound = false; + for ( var i=0 ; i 0 && sCurrentClass.indexOf(sNewClass) == -1 ) + { + /* We need to add a class */ + nTds[i].className = sCurrentClass + " " + sNewClass; + } + } + } + } + + + + /** + * Save the state of a table in a cookie such that the page can be reloaded + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnSaveState ( oSettings ) + { + if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying ) + { + return; + } + + /* Store the interesting variables */ + var i, iLen, bInfinite=oSettings.oScroll.bInfinite; + var oState = { + "iCreate": new Date().getTime(), + "iStart": (bInfinite ? 0 : oSettings._iDisplayStart), + "iEnd": (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd), + "iLength": oSettings._iDisplayLength, + "aaSorting": $.extend( true, [], oSettings.aaSorting ), + "oSearch": $.extend( true, {}, oSettings.oPreviousSearch ), + "aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ), + "abVisCols": [] + }; + + for ( i=0, iLen=oSettings.aoColumns.length ; i 4096 ) /* Magic 10 for padding */ + { + for ( var i=0, iLen=aCookies.length ; i 4096 ) { + if ( aOldCookies.length === 0 ) { + // Deleted all DT cookies and still not enough space. Can't state save + return; + } + + var old = aOldCookies.pop(); + document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+ + aParts.join('/') + "/"; + } + } + + document.cookie = sFullCookie; + } + + + /** + * Read an old cookie to get a cookie with an old table state + * @param {string} sName name of the cookie to read + * @returns {string} contents of the cookie - or null if no cookie with that name found + * @memberof DataTable#oApi + */ + function _fnReadCookie ( sName ) + { + var + aParts = window.location.pathname.split('/'), + sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=', + sCookieContents = document.cookie.split(';'); + + for( var i=0 ; i=0 ; i-- ) + { + aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) ); + } + + if ( sTrigger !== null ) + { + $(oSettings.oInstance).trigger(sTrigger, aArgs); + } + + return aRet; + } + + + /** + * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other + * library, then we use that as it is fast, safe and accurate. If the function isn't + * available then we need to built it ourselves - the inspiration for this function comes + * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is + * not perfect and absolutely should not be used as a replacement to json2.js - but it does + * do what we need, without requiring a dependency for DataTables. + * @param {object} o JSON object to be converted + * @returns {string} JSON string + * @memberof DataTable#oApi + */ + var _fnJsonString = (window.JSON) ? JSON.stringify : function( o ) + { + /* Not an object or array */ + var sType = typeof o; + if (sType !== "object" || o === null) + { + // simple data type + if (sType === "string") + { + o = '"'+o+'"'; + } + return o+""; + } + + /* If object or array, need to recurse over it */ + var + sProp, mValue, + json = [], + bArr = $.isArray(o); + + for (sProp in o) + { + mValue = o[sProp]; + sType = typeof mValue; + + if (sType === "string") + { + mValue = '"'+mValue+'"'; + } + else if (sType === "object" && mValue !== null) + { + mValue = _fnJsonString(mValue); + } + + json.push((bArr ? "" : '"'+sProp+'":') + mValue); + } + + return (bArr ? "[" : "{") + json + (bArr ? "]" : "}"); + }; + + + /** + * From some browsers (specifically IE6/7) we need special handling to work around browser + * bugs - this function is used to detect when these workarounds are needed. + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnBrowserDetect( oSettings ) + { + /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the + * width of the scrollbar, while other browsers ensure the inner element is contained + * without forcing scrolling + */ + var n = $( + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    ')[0]; + + document.body.appendChild( n ); + oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false; + document.body.removeChild( n ); + } + + + /** + * Perform a jQuery selector action on the table's TR elements (from the tbody) and + * return the resulting jQuery object. + * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on + * @param {object} [oOpts] Optional parameters for modifying the rows to be included + * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter + * criterion ("applied") or all TR elements (i.e. no filter). + * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. + * Can be either 'current', whereby the current sorting of the table is used, or + * 'original' whereby the original order the data was read into the table is used. + * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page + * ("current") or not ("all"). If 'current' is given, then order is assumed to be + * 'current' and filter is 'applied', regardless of what they might be given as. + * @returns {object} jQuery object, filtered by the given selector. + * @dtopt API + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Highlight every second row + * oTable.$('tr:odd').css('backgroundColor', 'blue'); + * } ); + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * + * // Filter to rows with 'Webkit' in them, add a background colour and then + * // remove the filter, thus highlighting the 'Webkit' rows only. + * oTable.fnFilter('Webkit'); + * oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue'); + * oTable.fnFilter(''); + * } ); + */ + this.$ = function ( sSelector, oOpts ) + { + var i, iLen, a = [], tr; + var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); + var aoData = oSettings.aoData; + var aiDisplay = oSettings.aiDisplay; + var aiDisplayMaster = oSettings.aiDisplayMaster; + + if ( !oOpts ) + { + oOpts = {}; + } + + oOpts = $.extend( {}, { + "filter": "none", // applied + "order": "current", // "original" + "page": "all" // current + }, oOpts ); + + // Current page implies that order=current and fitler=applied, since it is fairly + // senseless otherwise + if ( oOpts.page == 'current' ) + { + for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i + *
  • 1D array of data - add a single row with the data provided
  • + *
  • 2D array of arrays - add multiple rows in a single call
  • + *
  • object - data object when using mData
  • + *
  • array of objects - multiple data objects when using mData
  • + * + * @param {bool} [bRedraw=true] redraw the table or not + * @returns {array} An array of integers, representing the list of indexes in + * aoData ({@link DataTable.models.oSettings}) that have been added to + * the table. + * @dtopt API + * + * @example + * // Global var for counter + * var giCount = 2; + * + * $(document).ready(function() { + * $('#example').dataTable(); + * } ); + * + * function fnClickAddRow() { + * $('#example').dataTable().fnAddData( [ + * giCount+".1", + * giCount+".2", + * giCount+".3", + * giCount+".4" ] + * ); + * + * giCount++; + * } + */ + this.fnAddData = function( mData, bRedraw ) + { + if ( mData.length === 0 ) + { + return []; + } + + var aiReturn = []; + var iTest; + + /* Find settings from table node */ + var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); + + /* Check if we want to add multiple rows or not */ + if ( typeof mData[0] === "object" && mData[0] !== null ) + { + for ( var i=0 ; i= oSettings.fnRecordsDisplay() ) + { + oSettings._iDisplayStart -= oSettings._iDisplayLength; + if ( oSettings._iDisplayStart < 0 ) + { + oSettings._iDisplayStart = 0; + } + } + + if ( bRedraw === undefined || bRedraw ) + { + _fnCalculateEnd( oSettings ); + _fnDraw( oSettings ); + } + + return oData; + }; + + + /** + * Restore the table to it's original state in the DOM by removing all of DataTables + * enhancements, alterations to the DOM structure of the table and event listeners. + * @param {boolean} [bRemove=false] Completely remove the table from the DOM + * @dtopt API + * + * @example + * $(document).ready(function() { + * // This example is fairly pointless in reality, but shows how fnDestroy can be used + * var oTable = $('#example').dataTable(); + * oTable.fnDestroy(); + * } ); + */ + this.fnDestroy = function ( bRemove ) + { + var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); + var nOrig = oSettings.nTableWrapper.parentNode; + var nBody = oSettings.nTBody; + var i, iLen; + + bRemove = (bRemove===undefined) ? false : bRemove; + + /* Flag to note that the table is currently being destroyed - no action should be taken */ + oSettings.bDestroying = true; + + /* Fire off the destroy callbacks for plug-ins etc */ + _fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] ); + + /* If the table is not being removed, restore the hidden columns */ + if ( !bRemove ) + { + for ( i=0, iLen=oSettings.aoColumns.length ; itr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove(); + + /* When scrolling we had to break the table up - restore it */ + if ( oSettings.nTable != oSettings.nTHead.parentNode ) + { + $(oSettings.nTable).children('thead').remove(); + oSettings.nTable.appendChild( oSettings.nTHead ); + } + + if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode ) + { + $(oSettings.nTable).children('tfoot').remove(); + oSettings.nTable.appendChild( oSettings.nTFoot ); + } + + /* Remove the DataTables generated nodes, events and classes */ + oSettings.nTable.parentNode.removeChild( oSettings.nTable ); + $(oSettings.nTableWrapper).remove(); + + oSettings.aaSorting = []; + oSettings.aaSortingFixed = []; + _fnSortingClasses( oSettings ); + + $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') ); + + $('th, td', oSettings.nTHead).removeClass( [ + oSettings.oClasses.sSortable, + oSettings.oClasses.sSortableAsc, + oSettings.oClasses.sSortableDesc, + oSettings.oClasses.sSortableNone ].join(' ') + ); + if ( oSettings.bJUI ) + { + $('th span.'+oSettings.oClasses.sSortIcon + + ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove(); + + $('th, td', oSettings.nTHead).each( function () { + var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this); + var kids = jqWrapper.contents(); + $(this).append( kids ); + jqWrapper.remove(); + } ); + } + + /* Add the TR elements back into the table in their original order */ + if ( !bRemove && oSettings.nTableReinsertBefore ) + { + nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore ); + } + else if ( !bRemove ) + { + nOrig.appendChild( oSettings.nTable ); + } + + for ( i=0, iLen=oSettings.aoData.length ; i
    for filtering data. + *
      + *
    • + * Function input parameters: + *
        + *
      • {*} Data from the column cell to be prepared for filtering
      • + *
      + *
    • + *
    • + * Function return: + *
        + *
      • {string|null} Formatted string that will be used for the filtering.
      • + *
      + * + *
    + * + * Note that as of v1.9, it is typically preferable to use mData to prepare data for + * the different uses that DataTables can put the data to. Specifically mData when + * used as a function will give you a 'type' (sorting, filtering etc) that you can use to + * prepare the data as required for the different types. As such, this method is deprecated. + * @type object + * @default {} + * @deprecated + * + * @example + * $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) { + * return sData.replace(/\n/g," ").replace( /<.*?>/g, "" ); + * } + */ + "ofnSearch": {}, + + + /** + * Container for all private functions in DataTables so they can be exposed externally + * @type object + * @default {} + */ + "oApi": {}, + + + /** + * Storage for the various classes that DataTables uses + * @type object + * @default {} + */ + "oStdClasses": {}, + + + /** + * Storage for the various classes that DataTables uses - jQuery UI suitable + * @type object + * @default {} + */ + "oJUIClasses": {}, + + + /** + * Pagination plug-in methods - The style and controls of the pagination can significantly + * impact on how the end user interacts with the data in your table, and DataTables allows + * the addition of pagination controls by extending this object, which can then be enabled + * through the sPaginationType initialisation parameter. Each pagination type that + * is added is an object (the property name of which is what sPaginationType refers + * to) that has two properties, both methods that are used by DataTables to update the + * control's state. + *
      + *
    • + * fnInit - Initialisation of the paging controls. Called only during initialisation + * of the table. It is expected that this function will add the required DOM elements + * to the page for the paging controls to work. The element pointer + * 'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging + * controls (note that this is a 2D array to allow for multiple instances of each + * DataTables DOM element). It is suggested that you add the controls to this element + * as children + *
        + *
      • + * Function input parameters: + *
          + *
        • {object} DataTables settings object: see {@link DataTable.models.oSettings}.
        • + *
        • {node} Container into which the pagination controls must be inserted
        • + *
        • {function} Draw callback function - whenever the controls cause a page + * change, this method must be called to redraw the table.
        • + *
        + *
      • + *
      • + * Function return: + *
          + *
        • No return required
        • + *
        + * + *
      + * + *
    • + * fnInit - This function is called whenever the paging status of the table changes and is + * typically used to update classes and/or text of the paging controls to reflex the new + * status. + *
        + *
      • + * Function input parameters: + *
          + *
        • {object} DataTables settings object: see {@link DataTable.models.oSettings}.
        • + *
        • {function} Draw callback function - in case you need to redraw the table again + * or attach new event listeners
        • + *
        + *
      • + *
      • + * Function return: + *
          + *
        • No return required
        • + *
        + * + *
      + * + *
    + * @type object + * @default {} + * + * @example + * $.fn.dataTableExt.oPagination.four_button = { + * "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) { + * nFirst = document.createElement( 'span' ); + * nPrevious = document.createElement( 'span' ); + * nNext = document.createElement( 'span' ); + * nLast = document.createElement( 'span' ); + * + * nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) ); + * nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) ); + * nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) ); + * nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) ); + * + * nFirst.className = "paginate_button first"; + * nPrevious.className = "paginate_button previous"; + * nNext.className="paginate_button next"; + * nLast.className = "paginate_button last"; + * + * nPaging.appendChild( nFirst ); + * nPaging.appendChild( nPrevious ); + * nPaging.appendChild( nNext ); + * nPaging.appendChild( nLast ); + * + * $(nFirst).click( function () { + * oSettings.oApi._fnPageChange( oSettings, "first" ); + * fnCallbackDraw( oSettings ); + * } ); + * + * $(nPrevious).click( function() { + * oSettings.oApi._fnPageChange( oSettings, "previous" ); + * fnCallbackDraw( oSettings ); + * } ); + * + * $(nNext).click( function() { + * oSettings.oApi._fnPageChange( oSettings, "next" ); + * fnCallbackDraw( oSettings ); + * } ); + * + * $(nLast).click( function() { + * oSettings.oApi._fnPageChange( oSettings, "last" ); + * fnCallbackDraw( oSettings ); + * } ); + * + * $(nFirst).bind( 'selectstart', function () { return false; } ); + * $(nPrevious).bind( 'selectstart', function () { return false; } ); + * $(nNext).bind( 'selectstart', function () { return false; } ); + * $(nLast).bind( 'selectstart', function () { return false; } ); + * }, + * + * "fnUpdate": function ( oSettings, fnCallbackDraw ) { + * if ( !oSettings.aanFeatures.p ) { + * return; + * } + * + * // Loop over each instance of the pager + * var an = oSettings.aanFeatures.p; + * for ( var i=0, iLen=an.length ; i + *
  • + * Function input parameters: + *
      + *
    • {*} Data to compare to the second parameter
    • + *
    • {*} Data to compare to the first parameter
    • + *
    + *
  • + *
  • + * Function return: + *
      + *
    • {int} Sorting match: <0 if first parameter should be sorted lower than + * the second parameter, ===0 if the two parameters are equal and >0 if + * the first parameter should be sorted height than the second parameter.
    • + *
    + * + * + * @type object + * @default {} + * + * @example + * // Case-sensitive string sorting, with no pre-formatting method + * $.extend( $.fn.dataTableExt.oSort, { + * "string-case-asc": function(x,y) { + * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + * }, + * "string-case-desc": function(x,y) { + * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + * } + * } ); + * + * @example + * // Case-insensitive string sorting, with pre-formatting + * $.extend( $.fn.dataTableExt.oSort, { + * "string-pre": function(x) { + * return x.toLowerCase(); + * }, + * "string-asc": function(x,y) { + * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + * }, + * "string-desc": function(x,y) { + * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + * } + * } ); + */ + "oSort": {}, + + + /** + * Version string for plug-ins to check compatibility. Allowed format is + * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and + * e are optional + * @type string + * @default Version number + */ + "sVersion": DataTable.version, + + + /** + * How should DataTables report an error. Can take the value 'alert' or 'throw' + * @type string + * @default alert + */ + "sErrMode": "alert", + + + /** + * Store information for DataTables to access globally about other instances + * @namespace + * @private + */ + "_oExternConfig": { + /* int:iNextUnique - next unique number for an instance */ + "iNextUnique": 0 + } + }; + + + + + /** + * Template object for the way in which DataTables holds information about + * search information for the global filter and individual column filters. + * @namespace + */ + DataTable.models.oSearch = { + /** + * Flag to indicate if the filtering should be case insensitive or not + * @type boolean + * @default true + */ + "bCaseInsensitive": true, + + /** + * Applied search term + * @type string + * @default Empty string + */ + "sSearch": "", + + /** + * Flag to indicate if the search term should be interpreted as a + * regular expression (true) or not (false) and therefore and special + * regex characters escaped. + * @type boolean + * @default false + */ + "bRegex": false, + + /** + * Flag to indicate if DataTables is to use its smart filtering or not. + * @type boolean + * @default true + */ + "bSmart": true + }; + + + + + /** + * Template object for the way in which DataTables holds information about + * each individual row. This is the object format used for the settings + * aoData array. + * @namespace + */ + DataTable.models.oRow = { + /** + * TR element for the row + * @type node + * @default null + */ + "nTr": null, + + /** + * Data object from the original data source for the row. This is either + * an array if using the traditional form of DataTables, or an object if + * using mData options. The exact type will depend on the passed in + * data from the data source, or will be an array if using DOM a data + * source. + * @type array|object + * @default [] + */ + "_aData": [], + + /** + * Sorting data cache - this array is ostensibly the same length as the + * number of columns (although each index is generated only as it is + * needed), and holds the data that is used for sorting each column in the + * row. We do this cache generation at the start of the sort in order that + * the formatting of the sort data need be done only once for each cell + * per sort. This array should not be read from or written to by anything + * other than the master sorting methods. + * @type array + * @default [] + * @private + */ + "_aSortData": [], + + /** + * Array of TD elements that are cached for hidden rows, so they can be + * reinserted into the table if a column is made visible again (or to act + * as a store if a column is made hidden). Only hidden columns have a + * reference in the array. For non-hidden columns the value is either + * undefined or null. + * @type array nodes + * @default [] + * @private + */ + "_anHidden": [], + + /** + * Cache of the class name that DataTables has applied to the row, so we + * can quickly look at this variable rather than needing to do a DOM check + * on className for the nTr property. + * @type string + * @default Empty string + * @private + */ + "_sRowStripe": "" + }; + + + + /** + * Template object for the column information object in DataTables. This object + * is held in the settings aoColumns array and contains all the information that + * DataTables needs about each individual column. + * + * Note that this object is related to {@link DataTable.defaults.columns} + * but this one is the internal data store for DataTables's cache of columns. + * It should NOT be manipulated outside of DataTables. Any configuration should + * be done through the initialisation options. + * @namespace + */ + DataTable.models.oColumn = { + /** + * A list of the columns that sorting should occur on when this column + * is sorted. That this property is an array allows multi-column sorting + * to be defined for a column (for example first name / last name columns + * would benefit from this). The values are integers pointing to the + * columns to be sorted on (typically it will be a single integer pointing + * at itself, but that doesn't need to be the case). + * @type array + */ + "aDataSort": null, + + /** + * Define the sorting directions that are applied to the column, in sequence + * as the column is repeatedly sorted upon - i.e. the first value is used + * as the sorting direction when the column if first sorted (clicked on). + * Sort it again (click again) and it will move on to the next index. + * Repeat until loop. + * @type array + */ + "asSorting": null, + + /** + * Flag to indicate if the column is searchable, and thus should be included + * in the filtering or not. + * @type boolean + */ + "bSearchable": null, + + /** + * Flag to indicate if the column is sortable or not. + * @type boolean + */ + "bSortable": null, + + /** + * Deprecated When using fnRender, you have two options for what + * to do with the data, and this property serves as the switch. Firstly, you + * can have the sorting and filtering use the rendered value (true - default), + * or you can have the sorting and filtering us the original value (false). + * + * Please note that this option has now been deprecated and will be removed + * in the next version of DataTables. Please use mRender / mData rather than + * fnRender. + * @type boolean + * @deprecated + */ + "bUseRendered": null, + + /** + * Flag to indicate if the column is currently visible in the table or not + * @type boolean + */ + "bVisible": null, + + /** + * Flag to indicate to the type detection method if the automatic type + * detection should be used, or if a column type (sType) has been specified + * @type boolean + * @default true + * @private + */ + "_bAutoType": true, + + /** + * Developer definable function that is called whenever a cell is created (Ajax source, + * etc) or processed for input (DOM source). This can be used as a compliment to mRender + * allowing you to modify the DOM element (add background colour for example) when the + * element is available. + * @type function + * @param {element} nTd The TD node that has been created + * @param {*} sData The Data for the cell + * @param {array|object} oData The data for the whole row + * @param {int} iRow The row index for the aoData data store + * @default null + */ + "fnCreatedCell": null, + + /** + * Function to get data from a cell in a column. You should never + * access data directly through _aData internally in DataTables - always use + * the method attached to this property. It allows mData to function as + * required. This function is automatically assigned by the column + * initialisation method + * @type function + * @param {array|object} oData The data array/object for the array + * (i.e. aoData[]._aData) + * @param {string} sSpecific The specific data type you want to get - + * 'display', 'type' 'filter' 'sort' + * @returns {*} The data for the cell from the given row's data + * @default null + */ + "fnGetData": null, + + /** + * Deprecated Custom display function that will be called for the + * display of each cell in this column. + * + * Please note that this option has now been deprecated and will be removed + * in the next version of DataTables. Please use mRender / mData rather than + * fnRender. + * @type function + * @param {object} o Object with the following parameters: + * @param {int} o.iDataRow The row in aoData + * @param {int} o.iDataColumn The column in question + * @param {array} o.aData The data for the row in question + * @param {object} o.oSettings The settings object for this DataTables instance + * @returns {string} The string you which to use in the display + * @default null + * @deprecated + */ + "fnRender": null, + + /** + * Function to set data for a cell in the column. You should never + * set the data directly to _aData internally in DataTables - always use + * this method. It allows mData to function as required. This function + * is automatically assigned by the column initialisation method + * @type function + * @param {array|object} oData The data array/object for the array + * (i.e. aoData[]._aData) + * @param {*} sValue Value to set + * @default null + */ + "fnSetData": null, + + /** + * Property to read the value for the cells in the column from the data + * source array / object. If null, then the default content is used, if a + * function is given then the return from the function is used. + * @type function|int|string|null + * @default null + */ + "mData": null, + + /** + * Partner property to mData which is used (only when defined) to get + * the data - i.e. it is basically the same as mData, but without the + * 'set' option, and also the data fed to it is the result from mData. + * This is the rendering method to match the data method of mData. + * @type function|int|string|null + * @default null + */ + "mRender": null, + + /** + * Unique header TH/TD element for this column - this is what the sorting + * listener is attached to (if sorting is enabled.) + * @type node + * @default null + */ + "nTh": null, + + /** + * Unique footer TH/TD element for this column (if there is one). Not used + * in DataTables as such, but can be used for plug-ins to reference the + * footer for each column. + * @type node + * @default null + */ + "nTf": null, + + /** + * The class to apply to all TD elements in the table's TBODY for the column + * @type string + * @default null + */ + "sClass": null, + + /** + * When DataTables calculates the column widths to assign to each column, + * it finds the longest string in each column and then constructs a + * temporary table and reads the widths from that. The problem with this + * is that "mmm" is much wider then "iiii", but the latter is a longer + * string - thus the calculation can go wrong (doing it properly and putting + * it into an DOM object and measuring that is horribly(!) slow). Thus as + * a "work around" we provide this option. It will append its value to the + * text that is found to be the longest string for the column - i.e. padding. + * @type string + */ + "sContentPadding": null, + + /** + * Allows a default value to be given for a column's data, and will be used + * whenever a null data source is encountered (this can be because mData + * is set to null, or because the data source itself is null). + * @type string + * @default null + */ + "sDefaultContent": null, + + /** + * Name for the column, allowing reference to the column by name as well as + * by index (needs a lookup to work by name). + * @type string + */ + "sName": null, + + /** + * Custom sorting data type - defines which of the available plug-ins in + * afnSortData the custom sorting will use - if any is defined. + * @type string + * @default std + */ + "sSortDataType": 'std', + + /** + * Class to be applied to the header element when sorting on this column + * @type string + * @default null + */ + "sSortingClass": null, + + /** + * Class to be applied to the header element when sorting on this column - + * when jQuery UI theming is used. + * @type string + * @default null + */ + "sSortingClassJUI": null, + + /** + * Title of the column - what is seen in the TH element (nTh). + * @type string + */ + "sTitle": null, + + /** + * Column sorting and filtering type + * @type string + * @default null + */ + "sType": null, + + /** + * Width of the column + * @type string + * @default null + */ + "sWidth": null, + + /** + * Width of the column when it was first "encountered" + * @type string + * @default null + */ + "sWidthOrig": null + }; + + + + /** + * Initialisation options that can be given to DataTables at initialisation + * time. + * @namespace + */ + DataTable.defaults = { + /** + * An array of data to use for the table, passed in at initialisation which + * will be used in preference to any data which is already in the DOM. This is + * particularly useful for constructing tables purely in Javascript, for + * example with a custom Ajax call. + * @type array + * @default null + * @dtopt Option + * + * @example + * // Using a 2D array data source + * $(document).ready( function () { + * $('#example').dataTable( { + * "aaData": [ + * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], + * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], + * ], + * "aoColumns": [ + * { "sTitle": "Engine" }, + * { "sTitle": "Browser" }, + * { "sTitle": "Platform" }, + * { "sTitle": "Version" }, + * { "sTitle": "Grade" } + * ] + * } ); + * } ); + * + * @example + * // Using an array of objects as a data source (mData) + * $(document).ready( function () { + * $('#example').dataTable( { + * "aaData": [ + * { + * "engine": "Trident", + * "browser": "Internet Explorer 4.0", + * "platform": "Win 95+", + * "version": 4, + * "grade": "X" + * }, + * { + * "engine": "Trident", + * "browser": "Internet Explorer 5.0", + * "platform": "Win 95+", + * "version": 5, + * "grade": "C" + * } + * ], + * "aoColumns": [ + * { "sTitle": "Engine", "mData": "engine" }, + * { "sTitle": "Browser", "mData": "browser" }, + * { "sTitle": "Platform", "mData": "platform" }, + * { "sTitle": "Version", "mData": "version" }, + * { "sTitle": "Grade", "mData": "grade" } + * ] + * } ); + * } ); + */ + "aaData": null, + + + /** + * If sorting is enabled, then DataTables will perform a first pass sort on + * initialisation. You can define which column(s) the sort is performed upon, + * and the sorting direction, with this variable. The aaSorting array should + * contain an array for each column to be sorted initially containing the + * column's index and a direction string ('asc' or 'desc'). + * @type array + * @default [[0,'asc']] + * @dtopt Option + * + * @example + * // Sort by 3rd column first, and then 4th column + * $(document).ready( function() { + * $('#example').dataTable( { + * "aaSorting": [[2,'asc'], [3,'desc']] + * } ); + * } ); + * + * // No initial sorting + * $(document).ready( function() { + * $('#example').dataTable( { + * "aaSorting": [] + * } ); + * } ); + */ + "aaSorting": [[0,'asc']], + + + /** + * This parameter is basically identical to the aaSorting parameter, but + * cannot be overridden by user interaction with the table. What this means + * is that you could have a column (visible or hidden) which the sorting will + * always be forced on first - any sorting after that (from the user) will + * then be performed as required. This can be useful for grouping rows + * together. + * @type array + * @default null + * @dtopt Option + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "aaSortingFixed": [[0,'asc']] + * } ); + * } ) + */ + "aaSortingFixed": null, + + + /** + * This parameter allows you to readily specify the entries in the length drop + * down menu that DataTables shows when pagination is enabled. It can be + * either a 1D array of options which will be used for both the displayed + * option and the value, or a 2D array which will use the array in the first + * position as the value, and the array in the second position as the + * displayed options (useful for language strings such as 'All'). + * @type array + * @default [ 10, 25, 50, 100 ] + * @dtopt Option + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] + * } ); + * } ); + * + * @example + * // Setting the default display length as well as length menu + * // This is likely to be wanted if you remove the '10' option which + * // is the iDisplayLength default. + * $(document).ready( function() { + * $('#example').dataTable( { + * "iDisplayLength": 25, + * "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]] + * } ); + * } ); + */ + "aLengthMenu": [ 10, 25, 50, 100 ], + + + /** + * The aoColumns option in the initialisation parameter allows you to define + * details about the way individual columns behave. For a full list of + * column options that can be set, please see + * {@link DataTable.defaults.columns}. Note that if you use aoColumns to + * define your columns, you must have an entry in the array for every single + * column that you have in your table (these can be null if you don't which + * to specify any options). + * @member + */ + "aoColumns": null, + + /** + * Very similar to aoColumns, aoColumnDefs allows you to target a specific + * column, multiple columns, or all columns, using the aTargets property of + * each object in the array. This allows great flexibility when creating + * tables, as the aoColumnDefs arrays can be of any length, targeting the + * columns you specifically want. aoColumnDefs may use any of the column + * options available: {@link DataTable.defaults.columns}, but it _must_ + * have aTargets defined in each object in the array. Values in the aTargets + * array may be: + *
      + *
    • a string - class name will be matched on the TH for the column
    • + *
    • 0 or a positive integer - column index counting from the left
    • + *
    • a negative integer - column index counting from the right
    • + *
    • the string "_all" - all columns (i.e. assign a default)
    • + *
    + * @member + */ + "aoColumnDefs": null, + + + /** + * Basically the same as oSearch, this parameter defines the individual column + * filtering state at initialisation time. The array must be of the same size + * as the number of columns, and each element be an object with the parameters + * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also + * accepted and the default will be used. + * @type array + * @default [] + * @dtopt Option + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoSearchCols": [ + * null, + * { "sSearch": "My filter" }, + * null, + * { "sSearch": "^[0-9]", "bEscapeRegex": false } + * ] + * } ); + * } ) + */ + "aoSearchCols": [], + + + /** + * An array of CSS classes that should be applied to displayed rows. This + * array may be of any length, and DataTables will apply each class + * sequentially, looping when required. + * @type array + * @default null Will take the values determined by the oClasses.sStripe* + * options + * @dtopt Option + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ] + * } ); + * } ) + */ + "asStripeClasses": null, + + + /** + * Enable or disable automatic column width calculation. This can be disabled + * as an optimisation (it takes some time to calculate the widths) if the + * tables widths are passed in using aoColumns. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bAutoWidth": false + * } ); + * } ); + */ + "bAutoWidth": true, + + + /** + * Deferred rendering can provide DataTables with a huge speed boost when you + * are using an Ajax or JS data source for the table. This option, when set to + * true, will cause DataTables to defer the creation of the table elements for + * each row until they are needed for a draw - saving a significant amount of + * time. + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready( function() { + * var oTable = $('#example').dataTable( { + * "sAjaxSource": "sources/arrays.txt", + * "bDeferRender": true + * } ); + * } ); + */ + "bDeferRender": false, + + + /** + * Replace a DataTable which matches the given selector and replace it with + * one which has the properties of the new initialisation object passed. If no + * table matches the selector, then the new DataTable will be constructed as + * per normal. + * @type boolean + * @default false + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sScrollY": "200px", + * "bPaginate": false + * } ); + * + * // Some time later.... + * $('#example').dataTable( { + * "bFilter": false, + * "bDestroy": true + * } ); + * } ); + */ + "bDestroy": false, + + + /** + * Enable or disable filtering of data. Filtering in DataTables is "smart" in + * that it allows the end user to input multiple words (space separated) and + * will match a row containing those words, even if not in the order that was + * specified (this allow matching across multiple columns). Note that if you + * wish to use filtering in DataTables this must remain 'true' - to remove the + * default filtering input box and retain filtering abilities, please use + * {@link DataTable.defaults.sDom}. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bFilter": false + * } ); + * } ); + */ + "bFilter": true, + + + /** + * Enable or disable the table information display. This shows information + * about the data that is currently visible on the page, including information + * about filtered data if that action is being performed. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bInfo": false + * } ); + * } ); + */ + "bInfo": true, + + + /** + * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some + * slightly different and additional mark-up from what DataTables has + * traditionally used). + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bJQueryUI": true + * } ); + * } ); + */ + "bJQueryUI": false, + + + /** + * Allows the end user to select the size of a formatted page from a select + * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate). + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bLengthChange": false + * } ); + * } ); + */ + "bLengthChange": true, + + + /** + * Enable or disable pagination. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bPaginate": false + * } ); + * } ); + */ + "bPaginate": true, + + + /** + * Enable or disable the display of a 'processing' indicator when the table is + * being processed (e.g. a sort). This is particularly useful for tables with + * large amounts of data where it can take a noticeable amount of time to sort + * the entries. + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bProcessing": true + * } ); + * } ); + */ + "bProcessing": false, + + + /** + * Retrieve the DataTables object for the given selector. Note that if the + * table has already been initialised, this parameter will cause DataTables + * to simply return the object that has already been set up - it will not take + * account of any changes you might have made to the initialisation object + * passed to DataTables (setting this parameter to true is an acknowledgement + * that you understand this). bDestroy can be used to reinitialise a table if + * you need. + * @type boolean + * @default false + * @dtopt Options + * + * @example + * $(document).ready( function() { + * initTable(); + * tableActions(); + * } ); + * + * function initTable () + * { + * return $('#example').dataTable( { + * "sScrollY": "200px", + * "bPaginate": false, + * "bRetrieve": true + * } ); + * } + * + * function tableActions () + * { + * var oTable = initTable(); + * // perform API operations with oTable + * } + */ + "bRetrieve": false, + + + /** + * Indicate if DataTables should be allowed to set the padding / margin + * etc for the scrolling header elements or not. Typically you will want + * this. + * @type boolean + * @default true + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bScrollAutoCss": false, + * "sScrollY": "200px" + * } ); + * } ); + */ + "bScrollAutoCss": true, + + + /** + * When vertical (y) scrolling is enabled, DataTables will force the height of + * the table's viewport to the given height at all times (useful for layout). + * However, this can look odd when filtering data down to a small data set, + * and the footer is left "floating" further down. This parameter (when + * enabled) will cause DataTables to collapse the table's viewport down when + * the result set will fit within the given Y height. + * @type boolean + * @default false + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sScrollY": "200", + * "bScrollCollapse": true + * } ); + * } ); + */ + "bScrollCollapse": false, + + + /** + * Enable infinite scrolling for DataTables (to be used in combination with + * sScrollY). Infinite scrolling means that DataTables will continually load + * data as a user scrolls through a table, which is very useful for large + * dataset. This cannot be used with pagination, which is automatically + * disabled. Note - the Scroller extra for DataTables is recommended in + * in preference to this option. + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bScrollInfinite": true, + * "bScrollCollapse": true, + * "sScrollY": "200px" + * } ); + * } ); + */ + "bScrollInfinite": false, + + + /** + * Configure DataTables to use server-side processing. Note that the + * sAjaxSource parameter must also be given in order to give DataTables a + * source to obtain the required data for each draw. + * @type boolean + * @default false + * @dtopt Features + * @dtopt Server-side + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bServerSide": true, + * "sAjaxSource": "xhr.php" + * } ); + * } ); + */ + "bServerSide": false, + + + /** + * Enable or disable sorting of columns. Sorting of individual columns can be + * disabled by the "bSortable" option for each column. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bSort": false + * } ); + * } ); + */ + "bSort": true, + + + /** + * Allows control over whether DataTables should use the top (true) unique + * cell that is found for a single column, or the bottom (false - default). + * This is useful when using complex headers. + * @type boolean + * @default false + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bSortCellsTop": true + * } ); + * } ); + */ + "bSortCellsTop": false, + + + /** + * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and + * 'sorting_3' to the columns which are currently being sorted on. This is + * presented as a feature switch as it can increase processing time (while + * classes are removed and added) so for large data sets you might want to + * turn this off. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bSortClasses": false + * } ); + * } ); + */ + "bSortClasses": true, + + + /** + * Enable or disable state saving. When enabled a cookie will be used to save + * table display information such as pagination information, display length, + * filtering and sorting. As such when the end user reloads the page the + * display display will match what thy had previously set up. + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bStateSave": true + * } ); + * } ); + */ + "bStateSave": false, + + + /** + * Customise the cookie and / or the parameters being stored when using + * DataTables with state saving enabled. This function is called whenever + * the cookie is modified, and it expects a fully formed cookie string to be + * returned. Note that the data object passed in is a Javascript object which + * must be converted to a string (JSON.stringify for example). + * @type function + * @param {string} sName Name of the cookie defined by DataTables + * @param {object} oData Data to be stored in the cookie + * @param {string} sExpires Cookie expires string + * @param {string} sPath Path of the cookie to set + * @returns {string} Cookie formatted string (which should be encoded by + * using encodeURIComponent()) + * @dtopt Callbacks + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "fnCookieCallback": function (sName, oData, sExpires, sPath) { + * // Customise oData or sName or whatever else here + * return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath; + * } + * } ); + * } ); + */ + "fnCookieCallback": null, + + + /** + * This function is called when a TR element is created (and all TD child + * elements have been inserted), or registered if using a DOM source, allowing + * manipulation of the TR element (adding classes etc). + * @type function + * @param {node} nRow "TR" element for the current row + * @param {array} aData Raw data array for this row + * @param {int} iDataIndex The index of this row in aoData + * @dtopt Callbacks + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "fnCreatedRow": function( nRow, aData, iDataIndex ) { + * // Bold the grade for all 'A' grade browsers + * if ( aData[4] == "A" ) + * { + * $('td:eq(4)', nRow).html( 'A' ); + * } + * } + * } ); + * } ); + */ + "fnCreatedRow": null, + + + /** + * This function is called on every 'draw' event, and allows you to + * dynamically modify any aspect you want about the created DOM. + * @type function + * @param {object} oSettings DataTables settings object + * @dtopt Callbacks + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "fnDrawCallback": function( oSettings ) { + * alert( 'DataTables has redrawn the table' ); + * } + * } ); + * } ); + */ + "fnDrawCallback": null, + + + /** + * Identical to fnHeaderCallback() but for the table footer this function + * allows you to modify the table footer on every 'draw' even. + * @type function + * @param {node} nFoot "TR" element for the footer + * @param {array} aData Full table data (as derived from the original HTML) + * @param {int} iStart Index for the current display starting point in the + * display array + * @param {int} iEnd Index for the current display ending point in the + * display array + * @param {array int} aiDisplay Index array to translate the visual position + * to the full data array + * @dtopt Callbacks + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) { + * nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart; + * } + * } ); + * } ) + */ + "fnFooterCallback": null, + + + /** + * When rendering large numbers in the information element for the table + * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers + * to have a comma separator for the 'thousands' units (e.g. 1 million is + * rendered as "1,000,000") to help readability for the end user. This + * function will override the default method DataTables uses. + * @type function + * @member + * @param {int} iIn number to be formatted + * @returns {string} formatted string for DataTables to show the number + * @dtopt Callbacks + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "fnFormatNumber": function ( iIn ) { + * if ( iIn < 1000 ) { + * return iIn; + * } else { + * var + * s=(iIn+""), + * a=s.split(""), out="", + * iLen=s.length; + * + * for ( var i=0 ; i<iLen ; i++ ) { + * if ( i%3 === 0 && i !== 0 ) { + * out = "'"+out; + * } + * out = a[iLen-i-1]+out; + * } + * } + * return out; + * }; + * } ); + * } ); + */ + "fnFormatNumber": function ( iIn ) { + if ( iIn < 1000 ) + { + // A small optimisation for what is likely to be the majority of use cases + return iIn; + } + + var s=(iIn+""), a=s.split(""), out="", iLen=s.length; + + for ( var i=0 ; iA' ); + * } + * } + * } ); + * } ); + */ + "fnRowCallback": null, + + + /** + * This parameter allows you to override the default function which obtains + * the data from the server ($.getJSON) so something more suitable for your + * application. For example you could use POST data, or pull information from + * a Gears or AIR database. + * @type function + * @member + * @param {string} sSource HTTP source to obtain the data from (sAjaxSource) + * @param {array} aoData A key/value pair object containing the data to send + * to the server + * @param {function} fnCallback to be called on completion of the data get + * process that will draw the data on the page. + * @param {object} oSettings DataTables settings object + * @dtopt Callbacks + * @dtopt Server-side + * + * @example + * // POST data to server + * $(document).ready( function() { + * $('#example').dataTable( { + * "bProcessing": true, + * "bServerSide": true, + * "sAjaxSource": "xhr.php", + * "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) { + * oSettings.jqXHR = $.ajax( { + * "dataType": 'json', + * "type": "POST", + * "url": sSource, + * "data": aoData, + * "success": fnCallback + * } ); + * } + * } ); + * } ); + */ + "fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) { + oSettings.jqXHR = $.ajax( { + "url": sUrl, + "data": aoData, + "success": function (json) { + if ( json.sError ) { + oSettings.oApi._fnLog( oSettings, 0, json.sError ); + } + + $(oSettings.oInstance).trigger('xhr', [oSettings, json]); + fnCallback( json ); + }, + "dataType": "json", + "cache": false, + "type": oSettings.sServerMethod, + "error": function (xhr, error, thrown) { + if ( error == "parsererror" ) { + oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+ + "server could not be parsed. This is caused by a JSON formatting error." ); + } + } + } ); + }, + + + /** + * It is often useful to send extra data to the server when making an Ajax + * request - for example custom filtering information, and this callback + * function makes it trivial to send extra information to the server. The + * passed in parameter is the data set that has been constructed by + * DataTables, and you can add to this or modify it as you require. + * @type function + * @param {array} aoData Data array (array of objects which are name/value + * pairs) that has been constructed by DataTables and will be sent to the + * server. In the case of Ajax sourced data with server-side processing + * this will be an empty array, for server-side processing there will be a + * significant number of parameters! + * @returns {undefined} Ensure that you modify the aoData array passed in, + * as this is passed by reference. + * @dtopt Callbacks + * @dtopt Server-side + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bProcessing": true, + * "bServerSide": true, + * "sAjaxSource": "scripts/server_processing.php", + * "fnServerParams": function ( aoData ) { + * aoData.push( { "name": "more_data", "value": "my_value" } ); + * } + * } ); + * } ); + */ + "fnServerParams": null, + + + /** + * Load the table state. With this function you can define from where, and how, the + * state of a table is loaded. By default DataTables will load from its state saving + * cookie, but you might wish to use local storage (HTML5) or a server-side database. + * @type function + * @member + * @param {object} oSettings DataTables settings object + * @return {object} The DataTables state object to be loaded + * @dtopt Callbacks + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateLoad": function (oSettings) { + * var o; + * + * // Send an Ajax request to the server to get the data. Note that + * // this is a synchronous request. + * $.ajax( { + * "url": "/state_load", + * "async": false, + * "dataType": "json", + * "success": function (json) { + * o = json; + * } + * } ); + * + * return o; + * } + * } ); + * } ); + */ + "fnStateLoad": function ( oSettings ) { + var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance ); + var oData; + + try { + oData = (typeof $.parseJSON === 'function') ? + $.parseJSON(sData) : eval( '('+sData+')' ); + } catch (e) { + oData = null; + } + + return oData; + }, + + + /** + * Callback which allows modification of the saved state prior to loading that state. + * This callback is called when the table is loading state from the stored data, but + * prior to the settings object being modified by the saved state. Note that for + * plug-in authors, you should use the 'stateLoadParams' event to load parameters for + * a plug-in. + * @type function + * @param {object} oSettings DataTables settings object + * @param {object} oData The state object that is to be loaded + * @dtopt Callbacks + * + * @example + * // Remove a saved filter, so filtering is never loaded + * $(document).ready( function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateLoadParams": function (oSettings, oData) { + * oData.oSearch.sSearch = ""; + * } + * } ); + * } ); + * + * @example + * // Disallow state loading by returning false + * $(document).ready( function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateLoadParams": function (oSettings, oData) { + * return false; + * } + * } ); + * } ); + */ + "fnStateLoadParams": null, + + + /** + * Callback that is called when the state has been loaded from the state saving method + * and the DataTables settings object has been modified as a result of the loaded state. + * @type function + * @param {object} oSettings DataTables settings object + * @param {object} oData The state object that was loaded + * @dtopt Callbacks + * + * @example + * // Show an alert with the filtering value that was saved + * $(document).ready( function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateLoaded": function (oSettings, oData) { + * alert( 'Saved filter was: '+oData.oSearch.sSearch ); + * } + * } ); + * } ); + */ + "fnStateLoaded": null, + + + /** + * Save the table state. This function allows you to define where and how the state + * information for the table is stored - by default it will use a cookie, but you + * might want to use local storage (HTML5) or a server-side database. + * @type function + * @member + * @param {object} oSettings DataTables settings object + * @param {object} oData The state object to be saved + * @dtopt Callbacks + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateSave": function (oSettings, oData) { + * // Send an Ajax request to the server with the state object + * $.ajax( { + * "url": "/state_save", + * "data": oData, + * "dataType": "json", + * "method": "POST" + * "success": function () {} + * } ); + * } + * } ); + * } ); + */ + "fnStateSave": function ( oSettings, oData ) { + this.oApi._fnCreateCookie( + oSettings.sCookiePrefix+oSettings.sInstance, + this.oApi._fnJsonString(oData), + oSettings.iCookieDuration, + oSettings.sCookiePrefix, + oSettings.fnCookieCallback + ); + }, + + + /** + * Callback which allows modification of the state to be saved. Called when the table + * has changed state a new state save is required. This method allows modification of + * the state saving object prior to actually doing the save, including addition or + * other state properties or modification. Note that for plug-in authors, you should + * use the 'stateSaveParams' event to save parameters for a plug-in. + * @type function + * @param {object} oSettings DataTables settings object + * @param {object} oData The state object to be saved + * @dtopt Callbacks + * + * @example + * // Remove a saved filter, so filtering is never saved + * $(document).ready( function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateSaveParams": function (oSettings, oData) { + * oData.oSearch.sSearch = ""; + * } + * } ); + * } ); + */ + "fnStateSaveParams": null, + + + /** + * Duration of the cookie which is used for storing session information. This + * value is given in seconds. + * @type int + * @default 7200 (2 hours) + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "iCookieDuration": 60*60*24; // 1 day + * } ); + * } ) + */ + "iCookieDuration": 7200, + + + /** + * When enabled DataTables will not make a request to the server for the first + * page draw - rather it will use the data already on the page (no sorting etc + * will be applied to it), thus saving on an XHR at load time. iDeferLoading + * is used to indicate that deferred loading is required, but it is also used + * to tell DataTables how many records there are in the full table (allowing + * the information element and pagination to be displayed correctly). In the case + * where a filtering is applied to the table on initial load, this can be + * indicated by giving the parameter as an array, where the first element is + * the number of records available after filtering and the second element is the + * number of records without filtering (allowing the table information element + * to be shown correctly). + * @type int | array + * @default null + * @dtopt Options + * + * @example + * // 57 records available in the table, no filtering applied + * $(document).ready( function() { + * $('#example').dataTable( { + * "bServerSide": true, + * "sAjaxSource": "scripts/server_processing.php", + * "iDeferLoading": 57 + * } ); + * } ); + * + * @example + * // 57 records after filtering, 100 without filtering (an initial filter applied) + * $(document).ready( function() { + * $('#example').dataTable( { + * "bServerSide": true, + * "sAjaxSource": "scripts/server_processing.php", + * "iDeferLoading": [ 57, 100 ], + * "oSearch": { + * "sSearch": "my_filter" + * } + * } ); + * } ); + */ + "iDeferLoading": null, + + + /** + * Number of rows to display on a single page when using pagination. If + * feature enabled (bLengthChange) then the end user will be able to override + * this to a custom setting using a pop-up menu. + * @type int + * @default 10 + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "iDisplayLength": 50 + * } ); + * } ) + */ + "iDisplayLength": 10, + + + /** + * Define the starting point for data display when using DataTables with + * pagination. Note that this parameter is the number of records, rather than + * the page number, so if you have 10 records per page and want to start on + * the third page, it should be "20". + * @type int + * @default 0 + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "iDisplayStart": 20 + * } ); + * } ) + */ + "iDisplayStart": 0, + + + /** + * The scroll gap is the amount of scrolling that is left to go before + * DataTables will load the next 'page' of data automatically. You typically + * want a gap which is big enough that the scrolling will be smooth for the + * user, while not so large that it will load more data than need. + * @type int + * @default 100 + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bScrollInfinite": true, + * "bScrollCollapse": true, + * "sScrollY": "200px", + * "iScrollLoadGap": 50 + * } ); + * } ); + */ + "iScrollLoadGap": 100, + + + /** + * By default DataTables allows keyboard navigation of the table (sorting, paging, + * and filtering) by adding a tabindex attribute to the required elements. This + * allows you to tab through the controls and press the enter key to activate them. + * The tabindex is default 0, meaning that the tab follows the flow of the document. + * You can overrule this using this parameter if you wish. Use a value of -1 to + * disable built-in keyboard navigation. + * @type int + * @default 0 + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "iTabIndex": 1 + * } ); + * } ); + */ + "iTabIndex": 0, + + + /** + * All strings that DataTables uses in the user interface that it creates + * are defined in this object, allowing you to modified them individually or + * completely replace them all as required. + * @namespace + */ + "oLanguage": { + /** + * Strings that are used for WAI-ARIA labels and controls only (these are not + * actually visible on the page, but will be read by screenreaders, and thus + * must be internationalised as well). + * @namespace + */ + "oAria": { + /** + * ARIA label that is added to the table headers when the column may be + * sorted ascending by activing the column (click or return when focused). + * Note that the column header is prefixed to this string. + * @type string + * @default : activate to sort column ascending + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oAria": { + * "sSortAscending": " - click/return to sort ascending" + * } + * } + * } ); + * } ); + */ + "sSortAscending": ": activate to sort column ascending", + + /** + * ARIA label that is added to the table headers when the column may be + * sorted descending by activing the column (click or return when focused). + * Note that the column header is prefixed to this string. + * @type string + * @default : activate to sort column ascending + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oAria": { + * "sSortDescending": " - click/return to sort descending" + * } + * } + * } ); + * } ); + */ + "sSortDescending": ": activate to sort column descending" + }, + + /** + * Pagination string used by DataTables for the two built-in pagination + * control types ("two_button" and "full_numbers") + * @namespace + */ + "oPaginate": { + /** + * Text to use when using the 'full_numbers' type of pagination for the + * button to take the user to the first page. + * @type string + * @default First + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oPaginate": { + * "sFirst": "First page" + * } + * } + * } ); + * } ); + */ + "sFirst": "First", + + + /** + * Text to use when using the 'full_numbers' type of pagination for the + * button to take the user to the last page. + * @type string + * @default Last + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oPaginate": { + * "sLast": "Last page" + * } + * } + * } ); + * } ); + */ + "sLast": "Last", + + + /** + * Text to use for the 'next' pagination button (to take the user to the + * next page). + * @type string + * @default Next + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oPaginate": { + * "sNext": "Next page" + * } + * } + * } ); + * } ); + */ + "sNext": "Next", + + + /** + * Text to use for the 'previous' pagination button (to take the user to + * the previous page). + * @type string + * @default Previous + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oPaginate": { + * "sPrevious": "Previous page" + * } + * } + * } ); + * } ); + */ + "sPrevious": "Previous" + }, + + /** + * This string is shown in preference to sZeroRecords when the table is + * empty of data (regardless of filtering). Note that this is an optional + * parameter - if it is not given, the value of sZeroRecords will be used + * instead (either the default or given value). + * @type string + * @default No data available in table + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sEmptyTable": "No data available in table" + * } + * } ); + * } ); + */ + "sEmptyTable": "No data available in table", + + + /** + * This string gives information to the end user about the information that + * is current on display on the page. The _START_, _END_ and _TOTAL_ + * variables are all dynamically replaced as the table display updates, and + * can be freely moved or removed as the language requirements change. + * @type string + * @default Showing _START_ to _END_ of _TOTAL_ entries + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)" + * } + * } ); + * } ); + */ + "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", + + + /** + * Display information string for when the table is empty. Typically the + * format of this string should match sInfo. + * @type string + * @default Showing 0 to 0 of 0 entries + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfoEmpty": "No entries to show" + * } + * } ); + * } ); + */ + "sInfoEmpty": "Showing 0 to 0 of 0 entries", + + + /** + * When a user filters the information in a table, this string is appended + * to the information (sInfo) to give an idea of how strong the filtering + * is. The variable _MAX_ is dynamically updated. + * @type string + * @default (filtered from _MAX_ total entries) + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfoFiltered": " - filtering from _MAX_ records" + * } + * } ); + * } ); + */ + "sInfoFiltered": "(filtered from _MAX_ total entries)", + + + /** + * If can be useful to append extra information to the info string at times, + * and this variable does exactly that. This information will be appended to + * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are + * being used) at all times. + * @type string + * @default Empty string + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfoPostFix": "All records shown are derived from real information." + * } + * } ); + * } ); + */ + "sInfoPostFix": "", + + + /** + * DataTables has a build in number formatter (fnFormatNumber) which is used + * to format large numbers that are used in the table information. By + * default a comma is used, but this can be trivially changed to any + * character you wish with this parameter. + * @type string + * @default , + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfoThousands": "'" + * } + * } ); + * } ); + */ + "sInfoThousands": ",", + + + /** + * Detail the action that will be taken when the drop down menu for the + * pagination length option is changed. The '_MENU_' variable is replaced + * with a default select list of 10, 25, 50 and 100, and can be replaced + * with a custom select box if required. + * @type string + * @default Show _MENU_ entries + * @dtopt Language + * + * @example + * // Language change only + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sLengthMenu": "Display _MENU_ records" + * } + * } ); + * } ); + * + * @example + * // Language and options change + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sLengthMenu": 'Display records' + * } + * } ); + * } ); + */ + "sLengthMenu": "Show _MENU_ entries", + + + /** + * When using Ajax sourced data and during the first draw when DataTables is + * gathering the data, this message is shown in an empty row in the table to + * indicate to the end user the the data is being loaded. Note that this + * parameter is not used when loading data by server-side processing, just + * Ajax sourced data with client-side processing. + * @type string + * @default Loading... + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sLoadingRecords": "Please wait - loading..." + * } + * } ); + * } ); + */ + "sLoadingRecords": "Loading...", + + + /** + * Text which is displayed when the table is processing a user action + * (usually a sort command or similar). + * @type string + * @default Processing... + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sProcessing": "DataTables is currently busy" + * } + * } ); + * } ); + */ + "sProcessing": "Processing...", + + + /** + * Details the actions that will be taken when the user types into the + * filtering input text box. The variable "_INPUT_", if used in the string, + * is replaced with the HTML text box for the filtering input allowing + * control over where it appears in the string. If "_INPUT_" is not given + * then the input box is appended to the string automatically. + * @type string + * @default Search: + * @dtopt Language + * + * @example + * // Input text box will be appended at the end automatically + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sSearch": "Filter records:" + * } + * } ); + * } ); + * + * @example + * // Specify where the filter should appear + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sSearch": "Apply filter _INPUT_ to table" + * } + * } ); + * } ); + */ + "sSearch": "Search:", + + + /** + * All of the language information can be stored in a file on the + * server-side, which DataTables will look up if this parameter is passed. + * It must store the URL of the language file, which is in a JSON format, + * and the object has the same properties as the oLanguage object in the + * initialiser object (i.e. the above parameters). Please refer to one of + * the example language files to see how this works in action. + * @type string + * @default Empty string - i.e. disabled + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt" + * } + * } ); + * } ); + */ + "sUrl": "", + + + /** + * Text shown inside the table records when the is no information to be + * displayed after filtering. sEmptyTable is shown when there is simply no + * information in the table at all (regardless of filtering). + * @type string + * @default No matching records found + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sZeroRecords": "No records to display" + * } + * } ); + * } ); + */ + "sZeroRecords": "No matching records found" + }, + + + /** + * This parameter allows you to have define the global filtering state at + * initialisation time. As an object the "sSearch" parameter must be + * defined, but all other parameters are optional. When "bRegex" is true, + * the search string will be treated as a regular expression, when false + * (default) it will be treated as a straight string. When "bSmart" + * DataTables will use it's smart filtering methods (to word match at + * any point in the data), when false this will not be done. + * @namespace + * @extends DataTable.models.oSearch + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oSearch": {"sSearch": "Initial search"} + * } ); + * } ) + */ + "oSearch": $.extend( {}, DataTable.models.oSearch ), + + + /** + * By default DataTables will look for the property 'aaData' when obtaining + * data from an Ajax source or for server-side processing - this parameter + * allows that property to be changed. You can use Javascript dotted object + * notation to get a data source for multiple levels of nesting. + * @type string + * @default aaData + * @dtopt Options + * @dtopt Server-side + * + * @example + * // Get data from { "data": [...] } + * $(document).ready( function() { + * var oTable = $('#example').dataTable( { + * "sAjaxSource": "sources/data.txt", + * "sAjaxDataProp": "data" + * } ); + * } ); + * + * @example + * // Get data from { "data": { "inner": [...] } } + * $(document).ready( function() { + * var oTable = $('#example').dataTable( { + * "sAjaxSource": "sources/data.txt", + * "sAjaxDataProp": "data.inner" + * } ); + * } ); + */ + "sAjaxDataProp": "aaData", + + + /** + * You can instruct DataTables to load data from an external source using this + * parameter (use aData if you want to pass data in you already have). Simply + * provide a url a JSON object can be obtained from. This object must include + * the parameter 'aaData' which is the data source for the table. + * @type string + * @default null + * @dtopt Options + * @dtopt Server-side + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php" + * } ); + * } ) + */ + "sAjaxSource": null, + + + /** + * This parameter can be used to override the default prefix that DataTables + * assigns to a cookie when state saving is enabled. + * @type string + * @default SpryMedia_DataTables_ + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sCookiePrefix": "my_datatable_", + * } ); + * } ); + */ + "sCookiePrefix": "SpryMedia_DataTables_", + + + /** + * This initialisation variable allows you to specify exactly where in the + * DOM you want DataTables to inject the various controls it adds to the page + * (for example you might want the pagination controls at the top of the + * table). DIV elements (with or without a custom class) can also be added to + * aid styling. The follow syntax is used: + *
      + *
    • The following options are allowed: + *
        + *
      • 'l' - Length changing
      • 'f' - Filtering input + *
      • 't' - The table!
      • + *
      • 'i' - Information
      • + *
      • 'p' - Pagination
      • + *
      • 'r' - pRocessing
      • + *
      + *
    • + *
    • The following constants are allowed: + *
        + *
      • 'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')
      • + *
      • 'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')
      • + *
      + *
    • + *
    • The following syntax is expected: + *
        + *
      • '<' and '>' - div elements
      • + *
      • '<"class" and '>' - div with a class
      • + *
      • '<"#id" and '>' - div with an ID
      • + *
      + *
    • + *
    • Examples: + *
        + *
      • '<"wrapper"flipt>'
      • + *
      • '<lf<t>ip>'
      • + *
      + *
    • + *
    + * @type string + * @default lfrtip (when bJQueryUI is false) or + * <"H"lfr>t<"F"ip> (when bJQueryUI is true) + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sDom": '<"top"i>rt<"bottom"flp><"clear">' + * } ); + * } ); + */ + "sDom": "lfrtip", + + + /** + * DataTables features two different built-in pagination interaction methods + * ('two_button' or 'full_numbers') which present different page controls to + * the end user. Further methods can be added using the API (see below). + * @type string + * @default two_button + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sPaginationType": "full_numbers" + * } ); + * } ) + */ + "sPaginationType": "two_button", + + + /** + * Enable horizontal scrolling. When a table is too wide to fit into a certain + * layout, or you have a large number of columns in the table, you can enable + * x-scrolling to show the table in a viewport, which can be scrolled. This + * property can be any CSS unit, or a number (in which case it will be treated + * as a pixel measurement). + * @type string + * @default blank string - i.e. disabled + * @dtopt Features + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sScrollX": "100%", + * "bScrollCollapse": true + * } ); + * } ); + */ + "sScrollX": "", + + + /** + * This property can be used to force a DataTable to use more width than it + * might otherwise do when x-scrolling is enabled. For example if you have a + * table which requires to be well spaced, this parameter is useful for + * "over-sizing" the table, and thus forcing scrolling. This property can by + * any CSS unit, or a number (in which case it will be treated as a pixel + * measurement). + * @type string + * @default blank string - i.e. disabled + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sScrollX": "100%", + * "sScrollXInner": "110%" + * } ); + * } ); + */ + "sScrollXInner": "", + + + /** + * Enable vertical scrolling. Vertical scrolling will constrain the DataTable + * to the given height, and enable scrolling for any data which overflows the + * current viewport. This can be used as an alternative to paging to display + * a lot of data in a small area (although paging and scrolling can both be + * enabled at the same time). This property can be any CSS unit, or a number + * (in which case it will be treated as a pixel measurement). + * @type string + * @default blank string - i.e. disabled + * @dtopt Features + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sScrollY": "200px", + * "bPaginate": false + * } ); + * } ); + */ + "sScrollY": "", + + + /** + * Set the HTTP method that is used to make the Ajax call for server-side + * processing or Ajax sourced data. + * @type string + * @default GET + * @dtopt Options + * @dtopt Server-side + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bServerSide": true, + * "sAjaxSource": "scripts/post.php", + * "sServerMethod": "POST" + * } ); + * } ); + */ + "sServerMethod": "GET" + }; + + + + /** + * Column options that can be given to DataTables at initialisation time. + * @namespace + */ + DataTable.defaults.columns = { + /** + * Allows a column's sorting to take multiple columns into account when + * doing a sort. For example first name / last name columns make sense to + * do a multi-column sort over the two columns. + * @type array + * @default null Takes the value of the column index automatically + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] }, + * { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] }, + * { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "aDataSort": [ 0, 1 ] }, + * { "aDataSort": [ 1, 0 ] }, + * { "aDataSort": [ 2, 3, 4 ] }, + * null, + * null + * ] + * } ); + * } ); + */ + "aDataSort": null, + + + /** + * You can control the default sorting direction, and even alter the behaviour + * of the sort handler (i.e. only allow ascending sorting etc) using this + * parameter. + * @type array + * @default [ 'asc', 'desc' ] + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "asSorting": [ "asc" ], "aTargets": [ 1 ] }, + * { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] }, + * { "asSorting": [ "desc" ], "aTargets": [ 3 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * null, + * { "asSorting": [ "asc" ] }, + * { "asSorting": [ "desc", "asc", "asc" ] }, + * { "asSorting": [ "desc" ] }, + * null + * ] + * } ); + * } ); + */ + "asSorting": [ 'asc', 'desc' ], + + + /** + * Enable or disable filtering on the data in this column. + * @type boolean + * @default true + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "bSearchable": false, "aTargets": [ 0 ] } + * ] } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "bSearchable": false }, + * null, + * null, + * null, + * null + * ] } ); + * } ); + */ + "bSearchable": true, + + + /** + * Enable or disable sorting on this column. + * @type boolean + * @default true + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "bSortable": false, "aTargets": [ 0 ] } + * ] } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "bSortable": false }, + * null, + * null, + * null, + * null + * ] } ); + * } ); + */ + "bSortable": true, + + + /** + * Deprecated When using fnRender() for a column, you may wish + * to use the original data (before rendering) for sorting and filtering + * (the default is to used the rendered data that the user can see). This + * may be useful for dates etc. + * + * Please note that this option has now been deprecated and will be removed + * in the next version of DataTables. Please use mRender / mData rather than + * fnRender. + * @type boolean + * @default true + * @dtopt Columns + * @deprecated + */ + "bUseRendered": true, + + + /** + * Enable or disable the display of this column. + * @type boolean + * @default true + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "bVisible": false, "aTargets": [ 0 ] } + * ] } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "bVisible": false }, + * null, + * null, + * null, + * null + * ] } ); + * } ); + */ + "bVisible": true, + + + /** + * Developer definable function that is called whenever a cell is created (Ajax source, + * etc) or processed for input (DOM source). This can be used as a compliment to mRender + * allowing you to modify the DOM element (add background colour for example) when the + * element is available. + * @type function + * @param {element} nTd The TD node that has been created + * @param {*} sData The Data for the cell + * @param {array|object} oData The data for the whole row + * @param {int} iRow The row index for the aoData data store + * @param {int} iCol The column index for aoColumns + * @dtopt Columns + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ { + * "aTargets": [3], + * "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) { + * if ( sData == "1.7" ) { + * $(nTd).css('color', 'blue') + * } + * } + * } ] + * }); + * } ); + */ + "fnCreatedCell": null, + + + /** + * Deprecated Custom display function that will be called for the + * display of each cell in this column. + * + * Please note that this option has now been deprecated and will be removed + * in the next version of DataTables. Please use mRender / mData rather than + * fnRender. + * @type function + * @param {object} o Object with the following parameters: + * @param {int} o.iDataRow The row in aoData + * @param {int} o.iDataColumn The column in question + * @param {array} o.aData The data for the row in question + * @param {object} o.oSettings The settings object for this DataTables instance + * @param {object} o.mDataProp The data property used for this column + * @param {*} val The current cell value + * @returns {string} The string you which to use in the display + * @dtopt Columns + * @deprecated + */ + "fnRender": null, + + + /** + * The column index (starting from 0!) that you wish a sort to be performed + * upon when this column is selected for sorting. This can be used for sorting + * on hidden columns for example. + * @type int + * @default -1 Use automatically calculated column index + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "iDataSort": 1, "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "iDataSort": 1 }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "iDataSort": -1, + + + /** + * This parameter has been replaced by mData in DataTables to ensure naming + * consistency. mDataProp can still be used, as there is backwards compatibility + * in DataTables for this option, but it is strongly recommended that you use + * mData in preference to mDataProp. + * @name DataTable.defaults.columns.mDataProp + */ + + + /** + * This property can be used to read data from any JSON data source property, + * including deeply nested objects / properties. mData can be given in a + * number of different ways which effect its behaviour: + *
      + *
    • integer - treated as an array index for the data source. This is the + * default that DataTables uses (incrementally increased for each column).
    • + *
    • string - read an object property from the data source. Note that you can + * use Javascript dotted notation to read deep properties / arrays from the + * data source.
    • + *
    • null - the sDefaultContent option will be used for the cell (null + * by default, so you will need to specify the default content you want - + * typically an empty string). This can be useful on generated columns such + * as edit / delete action columns.
    • + *
    • function - the function given will be executed whenever DataTables + * needs to set or get the data for a cell in the column. The function + * takes three parameters: + *
        + *
      • {array|object} The data source for the row
      • + *
      • {string} The type call data requested - this will be 'set' when + * setting data or 'filter', 'display', 'type', 'sort' or undefined when + * gathering data. Note that when undefined is given for the type + * DataTables expects to get the raw data for the object back
      • + *
      • {*} Data to set when the second parameter is 'set'.
      • + *
      + * The return value from the function is not required when 'set' is the type + * of call, but otherwise the return is what will be used for the data + * requested.
    • + *
    + * + * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change + * reflects the flexibility of this property and is consistent with the naming of + * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as + * it automatically maps the old name to the new if required. + * @type string|int|function|null + * @default null Use automatically calculated column index + * @dtopt Columns + * + * @example + * // Read table data from objects + * $(document).ready( function() { + * var oTable = $('#example').dataTable( { + * "sAjaxSource": "sources/deep.txt", + * "aoColumns": [ + * { "mData": "engine" }, + * { "mData": "browser" }, + * { "mData": "platform.inner" }, + * { "mData": "platform.details.0" }, + * { "mData": "platform.details.1" } + * ] + * } ); + * } ); + * + * @example + * // Using mData as a function to provide different information for + * // sorting, filtering and display. In this case, currency (price) + * $(document).ready( function() { + * var oTable = $('#example').dataTable( { + * "aoColumnDefs": [ { + * "aTargets": [ 0 ], + * "mData": function ( source, type, val ) { + * if (type === 'set') { + * source.price = val; + * // Store the computed dislay and filter values for efficiency + * source.price_display = val=="" ? "" : "$"+numberFormat(val); + * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; + * return; + * } + * else if (type === 'display') { + * return source.price_display; + * } + * else if (type === 'filter') { + * return source.price_filter; + * } + * // 'sort', 'type' and undefined all just use the integer + * return source.price; + * } + * } ] + * } ); + * } ); + */ + "mData": null, + + + /** + * This property is the rendering partner to mData and it is suggested that + * when you want to manipulate data for display (including filtering, sorting etc) + * but not altering the underlying data for the table, use this property. mData + * can actually do everything this property can and more, but this parameter is + * easier to use since there is no 'set' option. Like mData is can be given + * in a number of different ways to effect its behaviour, with the addition of + * supporting array syntax for easy outputting of arrays (including arrays of + * objects): + *
      + *
    • integer - treated as an array index for the data source. This is the + * default that DataTables uses (incrementally increased for each column).
    • + *
    • string - read an object property from the data source. Note that you can + * use Javascript dotted notation to read deep properties / arrays from the + * data source and also array brackets to indicate that the data reader should + * loop over the data source array. When characters are given between the array + * brackets, these characters are used to join the data source array together. + * For example: "accounts[, ].name" would result in a comma separated list with + * the 'name' value from the 'accounts' array of objects.
    • + *
    • function - the function given will be executed whenever DataTables + * needs to set or get the data for a cell in the column. The function + * takes three parameters: + *
        + *
      • {array|object} The data source for the row (based on mData)
      • + *
      • {string} The type call data requested - this will be 'filter', 'display', + * 'type' or 'sort'.
      • + *
      • {array|object} The full data source for the row (not based on mData)
      • + *
      + * The return value from the function is what will be used for the data + * requested.
    • + *
    + * @type string|int|function|null + * @default null Use mData + * @dtopt Columns + * + * @example + * // Create a comma separated list from an array of objects + * $(document).ready( function() { + * var oTable = $('#example').dataTable( { + * "sAjaxSource": "sources/deep.txt", + * "aoColumns": [ + * { "mData": "engine" }, + * { "mData": "browser" }, + * { + * "mData": "platform", + * "mRender": "[, ].name" + * } + * ] + * } ); + * } ); + * + * @example + * // Use as a function to create a link from the data source + * $(document).ready( function() { + * var oTable = $('#example').dataTable( { + * "aoColumnDefs": [ + * { + * "aTargets": [ 0 ], + * "mData": "download_link", + * "mRender": function ( data, type, full ) { + * return 'Download'; + * } + * ] + * } ); + * } ); + */ + "mRender": null, + + + /** + * Change the cell type created for the column - either TD cells or TH cells. This + * can be useful as TH cells have semantic meaning in the table body, allowing them + * to act as a header for a row (you may wish to add scope='row' to the TH elements). + * @type string + * @default td + * @dtopt Columns + * + * @example + * // Make the first column use TH cells + * $(document).ready( function() { + * var oTable = $('#example').dataTable( { + * "aoColumnDefs": [ { + * "aTargets": [ 0 ], + * "sCellType": "th" + * } ] + * } ); + * } ); + */ + "sCellType": "td", + + + /** + * Class to give to each cell in this column. + * @type string + * @default Empty string + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sClass": "my_class", "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sClass": "my_class" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sClass": "", + + /** + * When DataTables calculates the column widths to assign to each column, + * it finds the longest string in each column and then constructs a + * temporary table and reads the widths from that. The problem with this + * is that "mmm" is much wider then "iiii", but the latter is a longer + * string - thus the calculation can go wrong (doing it properly and putting + * it into an DOM object and measuring that is horribly(!) slow). Thus as + * a "work around" we provide this option. It will append its value to the + * text that is found to be the longest string for the column - i.e. padding. + * Generally you shouldn't need this, and it is not documented on the + * general DataTables.net documentation + * @type string + * @default Empty string + * @dtopt Columns + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * null, + * null, + * null, + * { + * "sContentPadding": "mmm" + * } + * ] + * } ); + * } ); + */ + "sContentPadding": "", + + + /** + * Allows a default value to be given for a column's data, and will be used + * whenever a null data source is encountered (this can be because mData + * is set to null, or because the data source itself is null). + * @type string + * @default null + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { + * "mData": null, + * "sDefaultContent": "Edit", + * "aTargets": [ -1 ] + * } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * null, + * null, + * null, + * { + * "mData": null, + * "sDefaultContent": "Edit" + * } + * ] + * } ); + * } ); + */ + "sDefaultContent": null, + + + /** + * This parameter is only used in DataTables' server-side processing. It can + * be exceptionally useful to know what columns are being displayed on the + * client side, and to map these to database fields. When defined, the names + * also allow DataTables to reorder information from the server if it comes + * back in an unexpected order (i.e. if you switch your columns around on the + * client-side, your server-side code does not also need updating). + * @type string + * @default Empty string + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sName": "engine", "aTargets": [ 0 ] }, + * { "sName": "browser", "aTargets": [ 1 ] }, + * { "sName": "platform", "aTargets": [ 2 ] }, + * { "sName": "version", "aTargets": [ 3 ] }, + * { "sName": "grade", "aTargets": [ 4 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sName": "engine" }, + * { "sName": "browser" }, + * { "sName": "platform" }, + * { "sName": "version" }, + * { "sName": "grade" } + * ] + * } ); + * } ); + */ + "sName": "", + + + /** + * Defines a data source type for the sorting which can be used to read + * real-time information from the table (updating the internally cached + * version) prior to sorting. This allows sorting to occur on user editable + * elements such as form inputs. + * @type string + * @default std + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] }, + * { "sType": "numeric", "aTargets": [ 3 ] }, + * { "sSortDataType": "dom-select", "aTargets": [ 4 ] }, + * { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * null, + * null, + * { "sSortDataType": "dom-text" }, + * { "sSortDataType": "dom-text", "sType": "numeric" }, + * { "sSortDataType": "dom-select" }, + * { "sSortDataType": "dom-checkbox" } + * ] + * } ); + * } ); + */ + "sSortDataType": "std", + + + /** + * The title of this column. + * @type string + * @default null Derived from the 'TH' value for this column in the + * original HTML table. + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sTitle": "My column title", "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sTitle": "My column title" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sTitle": null, + + + /** + * The type allows you to specify how the data for this column will be sorted. + * Four types (string, numeric, date and html (which will strip HTML tags + * before sorting)) are currently available. Note that only date formats + * understood by Javascript's Date() object will be accepted as type date. For + * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric', + * 'date' or 'html' (by default). Further types can be adding through + * plug-ins. + * @type string + * @default null Auto-detected from raw data + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sType": "html", "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sType": "html" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sType": null, + + + /** + * Defining the width of the column, this parameter may take any CSS value + * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not + * been given a specific width through this interface ensuring that the table + * remains readable. + * @type string + * @default null Automatic + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sWidth": "20%", "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sWidth": "20%" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sWidth": null + }; + + + + /** + * DataTables settings object - this holds all the information needed for a + * given table, including configuration, data and current application of the + * table options. DataTables does not have a single instance for each DataTable + * with the settings attached to that instance, but rather instances of the + * DataTable "class" are created on-the-fly as needed (typically by a + * $().dataTable() call) and the settings object is then applied to that + * instance. + * + * Note that this object is related to {@link DataTable.defaults} but this + * one is the internal data store for DataTables's cache of columns. It should + * NOT be manipulated outside of DataTables. Any configuration should be done + * through the initialisation options. + * @namespace + * @todo Really should attach the settings object to individual instances so we + * don't need to create new instances on each $().dataTable() call (if the + * table already exists). It would also save passing oSettings around and + * into every single function. However, this is a very significant + * architecture change for DataTables and will almost certainly break + * backwards compatibility with older installations. This is something that + * will be done in 2.0. + */ + DataTable.models.oSettings = { + /** + * Primary features of DataTables and their enablement state. + * @namespace + */ + "oFeatures": { + + /** + * Flag to say if DataTables should automatically try to calculate the + * optimum table and columns widths (true) or not (false). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bAutoWidth": null, + + /** + * Delay the creation of TR and TD elements until they are actually + * needed by a driven page draw. This can give a significant speed + * increase for Ajax source and Javascript source data, but makes no + * difference at all fro DOM and server-side processing tables. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bDeferRender": null, + + /** + * Enable filtering on the table or not. Note that if this is disabled + * then there is no filtering at all on the table, including fnFilter. + * To just remove the filtering input use sDom and remove the 'f' option. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bFilter": null, + + /** + * Table information element (the 'Showing x of y records' div) enable + * flag. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bInfo": null, + + /** + * Present a user control allowing the end user to change the page size + * when pagination is enabled. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bLengthChange": null, + + /** + * Pagination enabled or not. Note that if this is disabled then length + * changing must also be disabled. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bPaginate": null, + + /** + * Processing indicator enable flag whenever DataTables is enacting a + * user request - typically an Ajax request for server-side processing. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bProcessing": null, + + /** + * Server-side processing enabled flag - when enabled DataTables will + * get all data from the server for every draw - there is no filtering, + * sorting or paging done on the client-side. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bServerSide": null, + + /** + * Sorting enablement flag. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSort": null, + + /** + * Apply a class to the columns which are being sorted to provide a + * visual highlight or not. This can slow things down when enabled since + * there is a lot of DOM interaction. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSortClasses": null, + + /** + * State saving enablement flag. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bStateSave": null + }, + + + /** + * Scrolling settings for a table. + * @namespace + */ + "oScroll": { + /** + * Indicate if DataTables should be allowed to set the padding / margin + * etc for the scrolling header elements or not. Typically you will want + * this. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bAutoCss": null, + + /** + * When the table is shorter in height than sScrollY, collapse the + * table container down to the height of the table (when true). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bCollapse": null, + + /** + * Infinite scrolling enablement flag. Now deprecated in favour of + * using the Scroller plug-in. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bInfinite": null, + + /** + * Width of the scrollbar for the web-browser's platform. Calculated + * during table initialisation. + * @type int + * @default 0 + */ + "iBarWidth": 0, + + /** + * Space (in pixels) between the bottom of the scrolling container and + * the bottom of the scrolling viewport before the next page is loaded + * when using infinite scrolling. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type int + */ + "iLoadGap": null, + + /** + * Viewport width for horizontal scrolling. Horizontal scrolling is + * disabled if an empty string. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sX": null, + + /** + * Width to expand the table to when using x-scrolling. Typically you + * should not need to use this. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @deprecated + */ + "sXInner": null, + + /** + * Viewport height for vertical scrolling. Vertical scrolling is disabled + * if an empty string. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sY": null + }, + + /** + * Language information for the table. + * @namespace + * @extends DataTable.defaults.oLanguage + */ + "oLanguage": { + /** + * Information callback function. See + * {@link DataTable.defaults.fnInfoCallback} + * @type function + * @default null + */ + "fnInfoCallback": null + }, + + /** + * Browser support parameters + * @namespace + */ + "oBrowser": { + /** + * Indicate if the browser incorrectly calculates width:100% inside a + * scrolling element (IE6/7) + * @type boolean + * @default false + */ + "bScrollOversize": false + }, + + /** + * Array referencing the nodes which are used for the features. The + * parameters of this object match what is allowed by sDom - i.e. + *
      + *
    • 'l' - Length changing
    • + *
    • 'f' - Filtering input
    • + *
    • 't' - The table!
    • + *
    • 'i' - Information
    • + *
    • 'p' - Pagination
    • + *
    • 'r' - pRocessing
    • + *
    + * @type array + * @default [] + */ + "aanFeatures": [], + + /** + * Store data information - see {@link DataTable.models.oRow} for detailed + * information. + * @type array + * @default [] + */ + "aoData": [], + + /** + * Array of indexes which are in the current display (after filtering etc) + * @type array + * @default [] + */ + "aiDisplay": [], + + /** + * Array of indexes for display - no filtering + * @type array + * @default [] + */ + "aiDisplayMaster": [], + + /** + * Store information about each column that is in use + * @type array + * @default [] + */ + "aoColumns": [], + + /** + * Store information about the table's header + * @type array + * @default [] + */ + "aoHeader": [], + + /** + * Store information about the table's footer + * @type array + * @default [] + */ + "aoFooter": [], + + /** + * Search data array for regular expression searching + * @type array + * @default [] + */ + "asDataSearch": [], + + /** + * Store the applied global search information in case we want to force a + * research or compare the old search to a new one. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @namespace + * @extends DataTable.models.oSearch + */ + "oPreviousSearch": {}, + + /** + * Store the applied search for each column - see + * {@link DataTable.models.oSearch} for the format that is used for the + * filtering information for each column. + * @type array + * @default [] + */ + "aoPreSearchCols": [], + + /** + * Sorting that is applied to the table. Note that the inner arrays are + * used in the following manner: + *
      + *
    • Index 0 - column number
    • + *
    • Index 1 - current sorting direction
    • + *
    • Index 2 - index of asSorting for this column
    • + *
    + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @todo These inner arrays should really be objects + */ + "aaSorting": null, + + /** + * Sorting that is always applied to the table (i.e. prefixed in front of + * aaSorting). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array|null + * @default null + */ + "aaSortingFixed": null, + + /** + * Classes to use for the striping of a table. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @default [] + */ + "asStripeClasses": null, + + /** + * If restoring a table - we should restore its striping classes as well + * @type array + * @default [] + */ + "asDestroyStripes": [], + + /** + * If restoring a table - we should restore its width + * @type int + * @default 0 + */ + "sDestroyWidth": 0, + + /** + * Callback functions array for every time a row is inserted (i.e. on a draw). + * @type array + * @default [] + */ + "aoRowCallback": [], + + /** + * Callback functions for the header on each draw. + * @type array + * @default [] + */ + "aoHeaderCallback": [], + + /** + * Callback function for the footer on each draw. + * @type array + * @default [] + */ + "aoFooterCallback": [], + + /** + * Array of callback functions for draw callback functions + * @type array + * @default [] + */ + "aoDrawCallback": [], + + /** + * Array of callback functions for row created function + * @type array + * @default [] + */ + "aoRowCreatedCallback": [], + + /** + * Callback functions for just before the table is redrawn. A return of + * false will be used to cancel the draw. + * @type array + * @default [] + */ + "aoPreDrawCallback": [], + + /** + * Callback functions for when the table has been initialised. + * @type array + * @default [] + */ + "aoInitComplete": [], + + + /** + * Callbacks for modifying the settings to be stored for state saving, prior to + * saving state. + * @type array + * @default [] + */ + "aoStateSaveParams": [], + + /** + * Callbacks for modifying the settings that have been stored for state saving + * prior to using the stored values to restore the state. + * @type array + * @default [] + */ + "aoStateLoadParams": [], + + /** + * Callbacks for operating on the settings object once the saved state has been + * loaded + * @type array + * @default [] + */ + "aoStateLoaded": [], + + /** + * Cache the table ID for quick access + * @type string + * @default Empty string + */ + "sTableId": "", + + /** + * The TABLE node for the main table + * @type node + * @default null + */ + "nTable": null, + + /** + * Permanent ref to the thead element + * @type node + * @default null + */ + "nTHead": null, + + /** + * Permanent ref to the tfoot element - if it exists + * @type node + * @default null + */ + "nTFoot": null, + + /** + * Permanent ref to the tbody element + * @type node + * @default null + */ + "nTBody": null, + + /** + * Cache the wrapper node (contains all DataTables controlled elements) + * @type node + * @default null + */ + "nTableWrapper": null, + + /** + * Indicate if when using server-side processing the loading of data + * should be deferred until the second draw. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + * @default false + */ + "bDeferLoading": false, + + /** + * Indicate if all required information has been read in + * @type boolean + * @default false + */ + "bInitialised": false, + + /** + * Information about open rows. Each object in the array has the parameters + * 'nTr' and 'nParent' + * @type array + * @default [] + */ + "aoOpenRows": [], + + /** + * Dictate the positioning of DataTables' control elements - see + * {@link DataTable.model.oInit.sDom}. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default null + */ + "sDom": null, + + /** + * Which type of pagination should be used. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default two_button + */ + "sPaginationType": "two_button", + + /** + * The cookie duration (for bStateSave) in seconds. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type int + * @default 0 + */ + "iCookieDuration": 0, + + /** + * The cookie name prefix. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default Empty string + */ + "sCookiePrefix": "", + + /** + * Callback function for cookie creation. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type function + * @default null + */ + "fnCookieCallback": null, + + /** + * Array of callback functions for state saving. Each array element is an + * object with the following parameters: + *
      + *
    • function:fn - function to call. Takes two parameters, oSettings + * and the JSON string to save that has been thus far created. Returns + * a JSON string to be inserted into a json object + * (i.e. '"param": [ 0, 1, 2]')
    • + *
    • string:sName - name of callback
    • + *
    + * @type array + * @default [] + */ + "aoStateSave": [], + + /** + * Array of callback functions for state loading. Each array element is an + * object with the following parameters: + *
      + *
    • function:fn - function to call. Takes two parameters, oSettings + * and the object stored. May return false to cancel state loading
    • + *
    • string:sName - name of callback
    • + *
    + * @type array + * @default [] + */ + "aoStateLoad": [], + + /** + * State that was loaded from the cookie. Useful for back reference + * @type object + * @default null + */ + "oLoadedState": null, + + /** + * Source url for AJAX data for the table. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default null + */ + "sAjaxSource": null, + + /** + * Property from a given object from which to read the table data from. This + * can be an empty string (when not server-side processing), in which case + * it is assumed an an array is given directly. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sAjaxDataProp": null, + + /** + * Note if draw should be blocked while getting data + * @type boolean + * @default true + */ + "bAjaxDataGet": true, + + /** + * The last jQuery XHR object that was used for server-side data gathering. + * This can be used for working with the XHR information in one of the + * callbacks + * @type object + * @default null + */ + "jqXHR": null, + + /** + * Function to get the server-side data. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type function + */ + "fnServerData": null, + + /** + * Functions which are called prior to sending an Ajax request so extra + * parameters can easily be sent to the server + * @type array + * @default [] + */ + "aoServerParams": [], + + /** + * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if + * required). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sServerMethod": null, + + /** + * Format numbers for display. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type function + */ + "fnFormatNumber": null, + + /** + * List of options that can be used for the user selectable length menu. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @default [] + */ + "aLengthMenu": null, + + /** + * Counter for the draws that the table does. Also used as a tracker for + * server-side processing + * @type int + * @default 0 + */ + "iDraw": 0, + + /** + * Indicate if a redraw is being done - useful for Ajax + * @type boolean + * @default false + */ + "bDrawing": false, + + /** + * Draw index (iDraw) of the last error when parsing the returned data + * @type int + * @default -1 + */ + "iDrawError": -1, + + /** + * Paging display length + * @type int + * @default 10 + */ + "_iDisplayLength": 10, + + /** + * Paging start point - aiDisplay index + * @type int + * @default 0 + */ + "_iDisplayStart": 0, + + /** + * Paging end point - aiDisplay index. Use fnDisplayEnd rather than + * this property to get the end point + * @type int + * @default 10 + * @private + */ + "_iDisplayEnd": 10, + + /** + * Server-side processing - number of records in the result set + * (i.e. before filtering), Use fnRecordsTotal rather than + * this property to get the value of the number of records, regardless of + * the server-side processing setting. + * @type int + * @default 0 + * @private + */ + "_iRecordsTotal": 0, + + /** + * Server-side processing - number of records in the current display set + * (i.e. after filtering). Use fnRecordsDisplay rather than + * this property to get the value of the number of records, regardless of + * the server-side processing setting. + * @type boolean + * @default 0 + * @private + */ + "_iRecordsDisplay": 0, + + /** + * Flag to indicate if jQuery UI marking and classes should be used. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bJUI": null, + + /** + * The classes to use for the table + * @type object + * @default {} + */ + "oClasses": {}, + + /** + * Flag attached to the settings object so you can check in the draw + * callback if filtering has been done in the draw. Deprecated in favour of + * events. + * @type boolean + * @default false + * @deprecated + */ + "bFiltered": false, + + /** + * Flag attached to the settings object so you can check in the draw + * callback if sorting has been done in the draw. Deprecated in favour of + * events. + * @type boolean + * @default false + * @deprecated + */ + "bSorted": false, + + /** + * Indicate that if multiple rows are in the header and there is more than + * one unique cell per column, if the top one (true) or bottom one (false) + * should be used for sorting / title by DataTables. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSortCellsTop": null, + + /** + * Initialisation object that is used for the table + * @type object + * @default null + */ + "oInit": null, + + /** + * Destroy callback functions - for plug-ins to attach themselves to the + * destroy so they can clean up markup and events. + * @type array + * @default [] + */ + "aoDestroyCallback": [], + + + /** + * Get the number of records in the current record set, before filtering + * @type function + */ + "fnRecordsTotal": function () + { + if ( this.oFeatures.bServerSide ) { + return parseInt(this._iRecordsTotal, 10); + } else { + return this.aiDisplayMaster.length; + } + }, + + /** + * Get the number of records in the current record set, after filtering + * @type function + */ + "fnRecordsDisplay": function () + { + if ( this.oFeatures.bServerSide ) { + return parseInt(this._iRecordsDisplay, 10); + } else { + return this.aiDisplay.length; + } + }, + + /** + * Set the display end point - aiDisplay index + * @type function + * @todo Should do away with _iDisplayEnd and calculate it on-the-fly here + */ + "fnDisplayEnd": function () + { + if ( this.oFeatures.bServerSide ) { + if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) { + return this._iDisplayStart+this.aiDisplay.length; + } else { + return Math.min( this._iDisplayStart+this._iDisplayLength, + this._iRecordsDisplay ); + } + } else { + return this._iDisplayEnd; + } + }, + + /** + * The DataTables object for this table + * @type object + * @default null + */ + "oInstance": null, + + /** + * Unique identifier for each instance of the DataTables object. If there + * is an ID on the table node, then it takes that value, otherwise an + * incrementing internal counter is used. + * @type string + * @default null + */ + "sInstance": null, + + /** + * tabindex attribute value that is added to DataTables control elements, allowing + * keyboard navigation of the table and its controls. + */ + "iTabIndex": 0, + + /** + * DIV container for the footer scrolling table if scrolling + */ + "nScrollHead": null, + + /** + * DIV container for the footer scrolling table if scrolling + */ + "nScrollFoot": null + }; + + /** + * Extension object for DataTables that is used to provide all extension options. + * + * Note that the DataTable.ext object is available through + * jQuery.fn.dataTable.ext where it may be accessed and manipulated. It is + * also aliased to jQuery.fn.dataTableExt for historic reasons. + * @namespace + * @extends DataTable.models.ext + */ + DataTable.ext = $.extend( true, {}, DataTable.models.ext ); + + $.extend( DataTable.ext.oStdClasses, { + "sTable": "dataTable", + + /* Two buttons buttons */ + "sPagePrevEnabled": "paginate_enabled_previous", + "sPagePrevDisabled": "paginate_disabled_previous", + "sPageNextEnabled": "paginate_enabled_next", + "sPageNextDisabled": "paginate_disabled_next", + "sPageJUINext": "", + "sPageJUIPrev": "", + + /* Full numbers paging buttons */ + "sPageButton": "paginate_button", + "sPageButtonActive": "paginate_active", + "sPageButtonStaticDisabled": "paginate_button paginate_button_disabled", + "sPageFirst": "first", + "sPagePrevious": "previous", + "sPageNext": "next", + "sPageLast": "last", + + /* Striping classes */ + "sStripeOdd": "odd", + "sStripeEven": "even", + + /* Empty row */ + "sRowEmpty": "dataTables_empty", + + /* Features */ + "sWrapper": "dataTables_wrapper", + "sFilter": "dataTables_filter", + "sInfo": "dataTables_info", + "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ + "sLength": "dataTables_length", + "sProcessing": "dataTables_processing", + + /* Sorting */ + "sSortAsc": "sorting_asc", + "sSortDesc": "sorting_desc", + "sSortable": "sorting", /* Sortable in both directions */ + "sSortableAsc": "sorting_asc_disabled", + "sSortableDesc": "sorting_desc_disabled", + "sSortableNone": "sorting_disabled", + "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ + "sSortJUIAsc": "", + "sSortJUIDesc": "", + "sSortJUI": "", + "sSortJUIAscAllowed": "", + "sSortJUIDescAllowed": "", + "sSortJUIWrapper": "", + "sSortIcon": "", + + /* Scrolling */ + "sScrollWrapper": "dataTables_scroll", + "sScrollHead": "dataTables_scrollHead", + "sScrollHeadInner": "dataTables_scrollHeadInner", + "sScrollBody": "dataTables_scrollBody", + "sScrollFoot": "dataTables_scrollFoot", + "sScrollFootInner": "dataTables_scrollFootInner", + + /* Misc */ + "sFooterTH": "", + "sJUIHeader": "", + "sJUIFooter": "" + } ); + + + $.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, { + /* Two buttons buttons */ + "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left", + "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled", + "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right", + "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled", + "sPageJUINext": "ui-icon ui-icon-circle-arrow-e", + "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w", + + /* Full numbers paging buttons */ + "sPageButton": "fg-button ui-button ui-state-default", + "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled", + "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled", + "sPageFirst": "first ui-corner-tl ui-corner-bl", + "sPageLast": "last ui-corner-tr ui-corner-br", + + /* Features */ + "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ + "ui-buttonset-multi paging_", /* Note that the type is postfixed */ + + /* Sorting */ + "sSortAsc": "ui-state-default", + "sSortDesc": "ui-state-default", + "sSortable": "ui-state-default", + "sSortableAsc": "ui-state-default", + "sSortableDesc": "ui-state-default", + "sSortableNone": "ui-state-default", + "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n", + "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s", + "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s", + "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n", + "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s", + "sSortJUIWrapper": "DataTables_sort_wrapper", + "sSortIcon": "DataTables_sort_icon", + + /* Scrolling */ + "sScrollHead": "dataTables_scrollHead ui-state-default", + "sScrollFoot": "dataTables_scrollFoot ui-state-default", + + /* Misc */ + "sFooterTH": "ui-state-default", + "sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix", + "sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix" + } ); + + /* + * Variable: oPagination + * Purpose: + * Scope: jQuery.fn.dataTableExt + */ + $.extend( DataTable.ext.oPagination, { + /* + * Variable: two_button + * Purpose: Standard two button (forward/back) pagination + * Scope: jQuery.fn.dataTableExt.oPagination + */ + "two_button": { + /* + * Function: oPagination.two_button.fnInit + * Purpose: Initialise dom elements required for pagination with forward/back buttons only + * Returns: - + * Inputs: object:oSettings - dataTables settings object + * node:nPaging - the DIV which contains this pagination control + * function:fnCallbackDraw - draw function which must be called on update + */ + "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) + { + var oLang = oSettings.oLanguage.oPaginate; + var oClasses = oSettings.oClasses; + var fnClickHandler = function ( e ) { + if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) ) + { + fnCallbackDraw( oSettings ); + } + }; + + var sAppend = (!oSettings.bJUI) ? + ''+oLang.sPrevious+''+ + ''+oLang.sNext+'' + : + ''+ + ''; + $(nPaging).append( sAppend ); + + var els = $('a', nPaging); + var nPrevious = els[0], + nNext = els[1]; + + oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler ); + oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler ); + + /* ID the first elements only */ + if ( !oSettings.aanFeatures.p ) + { + nPaging.id = oSettings.sTableId+'_paginate'; + nPrevious.id = oSettings.sTableId+'_previous'; + nNext.id = oSettings.sTableId+'_next'; + + nPrevious.setAttribute('aria-controls', oSettings.sTableId); + nNext.setAttribute('aria-controls', oSettings.sTableId); + } + }, + + /* + * Function: oPagination.two_button.fnUpdate + * Purpose: Update the two button pagination at the end of the draw + * Returns: - + * Inputs: object:oSettings - dataTables settings object + * function:fnCallbackDraw - draw function to call on page change + */ + "fnUpdate": function ( oSettings, fnCallbackDraw ) + { + if ( !oSettings.aanFeatures.p ) + { + return; + } + + var oClasses = oSettings.oClasses; + var an = oSettings.aanFeatures.p; + var nNode; + + /* Loop over each instance of the pager */ + for ( var i=0, iLen=an.length ; i'+oLang.sFirst+''+ + ''+oLang.sPrevious+''+ + ''+ + ''+oLang.sNext+''+ + ''+oLang.sLast+'' + ); + var els = $('a', nPaging); + var nFirst = els[0], + nPrev = els[1], + nNext = els[2], + nLast = els[3]; + + oSettings.oApi._fnBindAction( nFirst, {action: "first"}, fnClickHandler ); + oSettings.oApi._fnBindAction( nPrev, {action: "previous"}, fnClickHandler ); + oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler ); + oSettings.oApi._fnBindAction( nLast, {action: "last"}, fnClickHandler ); + + /* ID the first elements only */ + if ( !oSettings.aanFeatures.p ) + { + nPaging.id = oSettings.sTableId+'_paginate'; + nFirst.id =oSettings.sTableId+'_first'; + nPrev.id =oSettings.sTableId+'_previous'; + nNext.id =oSettings.sTableId+'_next'; + nLast.id =oSettings.sTableId+'_last'; + } + }, + + /* + * Function: oPagination.full_numbers.fnUpdate + * Purpose: Update the list of page buttons shows + * Returns: - + * Inputs: object:oSettings - dataTables settings object + * function:fnCallbackDraw - draw function to call on page change + */ + "fnUpdate": function ( oSettings, fnCallbackDraw ) + { + if ( !oSettings.aanFeatures.p ) + { + return; + } + + var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages; + var iPageCountHalf = Math.floor(iPageCount / 2); + var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength); + var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1; + var sList = ""; + var iStartButton, iEndButton, i, iLen; + var oClasses = oSettings.oClasses; + var anButtons, anStatic, nPaginateList, nNode; + var an = oSettings.aanFeatures.p; + var fnBind = function (j) { + oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) { + /* Use the information in the element to jump to the required page */ + oSettings.oApi._fnPageChange( oSettings, e.data.page ); + fnCallbackDraw( oSettings ); + e.preventDefault(); + } ); + }; + + /* Pages calculation */ + if ( oSettings._iDisplayLength === -1 ) + { + iStartButton = 1; + iEndButton = 1; + iCurrentPage = 1; + } + else if (iPages < iPageCount) + { + iStartButton = 1; + iEndButton = iPages; + } + else if (iCurrentPage <= iPageCountHalf) + { + iStartButton = 1; + iEndButton = iPageCount; + } + else if (iCurrentPage >= (iPages - iPageCountHalf)) + { + iStartButton = iPages - iPageCount + 1; + iEndButton = iPages; + } + else + { + iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1; + iEndButton = iStartButton + iPageCount - 1; + } + + + /* Build the dynamic list */ + for ( i=iStartButton ; i<=iEndButton ; i++ ) + { + sList += (iCurrentPage !== i) ? + ''+oSettings.fnFormatNumber(i)+'' : + ''+oSettings.fnFormatNumber(i)+''; + } + + /* Loop over each instance of the pager */ + for ( i=0, iLen=an.length ; i y) ? 1 : 0)); + }, + + "string-desc": function ( x, y ) + { + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + }, + + + /* + * html sorting (ignore html tags) + */ + "html-pre": function ( a ) + { + return a.replace( /<.*?>/g, "" ).toLowerCase(); + }, + + "html-asc": function ( x, y ) + { + return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + }, + + "html-desc": function ( x, y ) + { + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + }, + + + /* + * date sorting + */ + "date-pre": function ( a ) + { + var x = Date.parse( a ); + + if ( isNaN(x) || x==="" ) + { + x = Date.parse( "01/01/1970 00:00:00" ); + } + return x; + }, + + "date-asc": function ( x, y ) + { + return x - y; + }, + + "date-desc": function ( x, y ) + { + return y - x; + }, + + + /* + * numerical sorting + */ + "numeric-pre": function ( a ) + { + return (a=="-" || a==="") ? 0 : a*1; + }, + + "numeric-asc": function ( x, y ) + { + return x - y; + }, + + "numeric-desc": function ( x, y ) + { + return y - x; + } + } ); + + + $.extend( DataTable.ext.aTypes, [ + /* + * Function: - + * Purpose: Check to see if a string is numeric + * Returns: string:'numeric' or null + * Inputs: mixed:sText - string to check + */ + function ( sData ) + { + /* Allow zero length strings as a number */ + if ( typeof sData === 'number' ) + { + return 'numeric'; + } + else if ( typeof sData !== 'string' ) + { + return null; + } + + var sValidFirstChars = "0123456789-"; + var sValidChars = "0123456789."; + var Char; + var bDecimal = false; + + /* Check for a valid first char (no period and allow negatives) */ + Char = sData.charAt(0); + if (sValidFirstChars.indexOf(Char) == -1) + { + return null; + } + + /* Check all the other characters are valid */ + for ( var i=1 ; i') != -1 ) + { + return 'html'; + } + return null; + } + ] ); + + + // jQuery aliases + $.fn.DataTable = DataTable; + $.fn.dataTable = DataTable; + $.fn.dataTableSettings = DataTable.settings; + $.fn.dataTableExt = DataTable.ext; + + + // Information about events fired by DataTables - for documentation. + /** + * Draw event, fired whenever the table is redrawn on the page, at the same point as + * fnDrawCallback. This may be useful for binding events or performing calculations when + * the table is altered at all. + * @name DataTable#draw + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Filter event, fired when the filtering applied to the table (using the build in global + * global filter, or column filters) is altered. + * @name DataTable#filter + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Page change event, fired when the paging of the table is altered. + * @name DataTable#page + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Sort event, fired when the sorting applied to the table is altered. + * @name DataTable#sort + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * DataTables initialisation complete event, fired when the table is fully drawn, + * including Ajax data loaded, if Ajax data is required. + * @name DataTable#init + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The JSON object request from the server - only + * present if client-side Ajax sourced data is used
  • + */ + + /** + * State save event, fired when the table has changed state a new state save is required. + * This method allows modification of the state saving object prior to actually doing the + * save, including addition or other state properties (for plug-ins) or modification + * of a DataTables core property. + * @name DataTable#stateSaveParams + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The state information to be saved + */ + + /** + * State load event, fired when the table is loading state from the stored data, but + * prior to the settings object being modified by the saved state - allowing modification + * of the saved state is required or loading of state for a plug-in. + * @name DataTable#stateLoadParams + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The saved state information + */ + + /** + * State loaded event, fired when state has been loaded from stored data and the settings + * object has been modified by the loaded data. + * @name DataTable#stateLoaded + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The saved state information + */ + + /** + * Processing event, fired when DataTables is doing some kind of processing (be it, + * sort, filter or anything else). Can be used to indicate to the end user that + * there is something happening, or that something has finished. + * @name DataTable#processing + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {boolean} bShow Flag for if DataTables is doing processing or not + */ + + /** + * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to + * made to the server for new data (note that this trigger is called in fnServerData, + * if you override fnServerData and which to use this event, you need to trigger it in + * you success function). + * @name DataTable#xhr + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + * @param {object} json JSON returned from the server + */ + + /** + * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing + * the bDestroy:true parameter in the initialisation object. This can be used to remove + * bound events, added DOM nodes, etc. + * @name DataTable#destroy + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ +})); + +}(window, document)); + diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/data-tables/jquery.dataTables-1.9.4.min.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/data-tables/jquery.dataTables-1.9.4.min.js index 02694a4a..c73ad54c 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/data-tables/jquery.dataTables-1.9.4.min.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/data-tables/jquery.dataTables-1.9.4.min.js @@ -1,155 +1,155 @@ -/* - * File: jquery.dataTables.min.js - * Version: 1.9.4 - * Author: Allan Jardine (www.sprymedia.co.uk) - * Info: www.datatables.net - * - * Copyright 2008-2012 Allan Jardine, all rights reserved. - * - * This source file is free software, under either the GPL v2 license or a - * BSD style license, available at: - * http://datatables.net/license_gpl2 - * http://datatables.net/license_bsd - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - */ -(function(X,l,n){var L=function(h){var j=function(e){function o(a,b){var c=j.defaults.columns,d=a.aoColumns.length,c=h.extend({},j.models.oColumn,c,{sSortingClass:a.oClasses.sSortable,sSortingClassJUI:a.oClasses.sSortJUI,nTh:b?b:l.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.oDefaults:d});a.aoColumns.push(c);if(a.aoPreSearchCols[d]===n||null===a.aoPreSearchCols[d])a.aoPreSearchCols[d]=h.extend({},j.models.oSearch);else if(c=a.aoPreSearchCols[d], -c.bRegex===n&&(c.bRegex=!0),c.bSmart===n&&(c.bSmart=!0),c.bCaseInsensitive===n)c.bCaseInsensitive=!0;m(a,d,null)}function m(a,b,c){var d=a.aoColumns[b];c!==n&&null!==c&&(c.mDataProp&&!c.mData&&(c.mData=c.mDataProp),c.sType!==n&&(d.sType=c.sType,d._bAutoType=!1),h.extend(d,c),p(d,c,"sWidth","sWidthOrig"),c.iDataSort!==n&&(d.aDataSort=[c.iDataSort]),p(d,c,"aDataSort"));var i=d.mRender?Q(d.mRender):null,f=Q(d.mData);d.fnGetData=function(a,b){var c=f(a,b);return d.mRender&&b&&""!==b?i(c,b,a):c};d.fnSetData= -L(d.mData);a.oFeatures.bSort||(d.bSortable=!1);!d.bSortable||-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableNone,d.sSortingClassJUI=""):-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortable,d.sSortingClassJUI=a.oClasses.sSortJUI):-1!=h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableAsc,d.sSortingClassJUI=a.oClasses.sSortJUIAscAllowed):-1== -h.inArray("asc",d.asSorting)&&-1!=h.inArray("desc",d.asSorting)&&(d.sSortingClass=a.oClasses.sSortableDesc,d.sSortingClassJUI=a.oClasses.sSortJUIDescAllowed)}function k(a){if(!1===a.oFeatures.bAutoWidth)return!1;da(a);for(var b=0,c=a.aoColumns.length;bj[f])d(a.aoColumns.length+j[f],b[i]);else if("string"===typeof j[f]){e=0;for(w=a.aoColumns.length;eb&&a[d]--; -1!=c&&a.splice(c,1)}function S(a,b,c){var d=a.aoColumns[c];return d.fnRender({iDataRow:b,iDataColumn:c,oSettings:a,aData:a.aoData[b]._aData,mDataProp:d.mData},v(a,b,c,"display"))}function ea(a,b){var c=a.aoData[b],d;if(null===c.nTr){c.nTr=l.createElement("tr");c.nTr._DT_RowIndex=b;c._aData.DT_RowId&&(c.nTr.id=c._aData.DT_RowId);c._aData.DT_RowClass&& -(c.nTr.className=c._aData.DT_RowClass);for(var i=0,f=a.aoColumns.length;i=a.fnRecordsDisplay()?0:a.iInitDisplayStart,a.iInitDisplayStart=-1,y(a));if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++;else if(a.oFeatures.bServerSide){if(!a.bDestroying&&!wa(a))return}else a.iDraw++;if(0!==a.aiDisplay.length){var g= -a._iDisplayStart;d=a._iDisplayEnd;a.oFeatures.bServerSide&&(g=0,d=a.aoData.length);for(;g
    ")[0];a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=h('
    ')[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var c=a.nTableWrapper,d=a.sDom.split(""),i,f,g,e,w,o,k,m=0;m
    ")[0];w=d[m+ -1];if("'"==w||'"'==w){o="";for(k=2;d[m+k]!=w;)o+=d[m+k],k++;"H"==o?o=a.oClasses.sJUIHeader:"F"==o&&(o=a.oClasses.sJUIFooter);-1!=o.indexOf(".")?(w=o.split("."),e.id=w[0].substr(1,w[0].length-1),e.className=w[1]):"#"==o.charAt(0)?e.id=o.substr(1,o.length-1):e.className=o;m+=k}c.appendChild(e);c=e}else if(">"==g)c=c.parentNode;else if("l"==g&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange)i=ya(a),f=1;else if("f"==g&&a.oFeatures.bFilter)i=za(a),f=1;else if("r"==g&&a.oFeatures.bProcessing)i=Aa(a),f= -1;else if("t"==g)i=Ba(a),f=1;else if("i"==g&&a.oFeatures.bInfo)i=Ca(a),f=1;else if("p"==g&&a.oFeatures.bPaginate)i=Da(a),f=1;else if(0!==j.ext.aoFeatures.length){e=j.ext.aoFeatures;k=0;for(w=e.length;k'):""===c?'':c+' ',d=l.createElement("div");d.className=a.oClasses.sFilter;d.innerHTML="";a.aanFeatures.f||(d.id=a.sTableId+"_filter");c=h('input[type="text"]',d);d._DT_Input=c[0];c.val(b.sSearch.replace('"',"""));c.bind("keyup.DT",function(){for(var c=a.aanFeatures.f,d=this.value===""?"":this.value, -g=0,e=c.length;g=b.length)a.aiDisplay.splice(0,a.aiDisplay.length),a.aiDisplay=a.aiDisplayMaster.slice();else if(a.aiDisplay.length==a.aiDisplayMaster.length||i.sSearch.length>b.length||1==c||0!==b.indexOf(i.sSearch)){a.aiDisplay.splice(0, -a.aiDisplay.length);la(a,1);for(b=0;b").html(c).text()); -return c.replace(/[\n\r]/g," ")}function ma(a,b,c,d){if(c)return a=b?a.split(" "):oa(a).split(" "),a="^(?=.*?"+a.join(")(?=.*?")+").*$",RegExp(a,d?"i":"");a=b?a:oa(a);return RegExp(a,d?"i":"")}function Ja(a,b){return"function"===typeof j.ext.ofnSearch[b]?j.ext.ofnSearch[b](a):null===a?"":"html"==b?a.replace(/[\r\n]/g," ").replace(/<.*?>/g,""):"string"===typeof a?a.replace(/[\r\n]/g," "):a}function oa(a){return a.replace(RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"), -"\\$1")}function Ca(a){var b=l.createElement("div");b.className=a.oClasses.sInfo;a.aanFeatures.i||(a.aoDrawCallback.push({fn:Ka,sName:"information"}),b.id=a.sTableId+"_info");a.nTable.setAttribute("aria-describedby",a.sTableId+"_info");return b}function Ka(a){if(a.oFeatures.bInfo&&0!==a.aanFeatures.i.length){var b=a.oLanguage,c=a._iDisplayStart+1,d=a.fnDisplayEnd(),i=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),g;g=0===f?b.sInfoEmpty:b.sInfo;f!=i&&(g+=" "+b.sInfoFiltered);g+=b.sInfoPostFix;g=ja(a,g); -null!==b.fnInfoCallback&&(g=b.fnInfoCallback.call(a.oInstance,a,c,d,i,f,g));a=a.aanFeatures.i;b=0;for(c=a.length;b",c,d,i=a.aLengthMenu;if(2==i.length&&"object"===typeof i[0]&&"object"===typeof i[1]){c=0;for(d=i[0].length;c'+i[1][c]+""}else{c=0;for(d=i.length;c'+i[c]+""}b+="";i=l.createElement("div");a.aanFeatures.l|| -(i.id=a.sTableId+"_length");i.className=a.oClasses.sLength;i.innerHTML="";h('select option[value="'+a._iDisplayLength+'"]',i).attr("selected",!0);h("select",i).bind("change.DT",function(){var b=h(this).val(),i=a.aanFeatures.l;c=0;for(d=i.length;ca.aiDisplay.length||-1==a._iDisplayLength?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Da(a){if(a.oScroll.bInfinite)return null;var b=l.createElement("div");b.className=a.oClasses.sPaging+a.sPaginationType;j.ext.oPagination[a.sPaginationType].fnInit(a, -b,function(a){y(a);x(a)});a.aanFeatures.p||a.aoDrawCallback.push({fn:function(a){j.ext.oPagination[a.sPaginationType].fnUpdate(a,function(a){y(a);x(a)})},sName:"pagination"});return b}function qa(a,b){var c=a._iDisplayStart;if("number"===typeof b)a._iDisplayStart=b*a._iDisplayLength,a._iDisplayStart>a.fnRecordsDisplay()&&(a._iDisplayStart=0);else if("first"==b)a._iDisplayStart=0;else if("previous"==b)a._iDisplayStart=0<=a._iDisplayLength?a._iDisplayStart-a._iDisplayLength:0,0>a._iDisplayStart&&(a._iDisplayStart= -0);else if("next"==b)0<=a._iDisplayLength?a._iDisplayStart+a._iDisplayLengthh(a.nTable).height()-a.oScroll.iLoadGap&&a.fnDisplayEnd()d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(h(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else""!==a.oScroll.sXInner?a.nTable.style.width= -q(a.oScroll.sXInner):i==h(d).width()&&h(d).height()i-a.oScroll.iBarWidth&&(a.nTable.style.width=q(i))):a.nTable.style.width=q(i);i=h(a.nTable).outerWidth();C(s,e);C(function(a){p.push(q(h(a).width()))},e);C(function(a,b){a.style.width=p[b]},g);h(e).height(0);null!==a.nTFoot&&(C(s,j),C(function(a){n.push(q(h(a).width()))},j),C(function(a,b){a.style.width=n[b]},o),h(j).height(0));C(function(a,b){a.innerHTML= -"";a.style.width=p[b]},e);null!==a.nTFoot&&C(function(a,b){a.innerHTML="";a.style.width=n[b]},j);if(h(a.nTable).outerWidth()d.offsetHeight||"scroll"==h(d).css("overflow-y")?i+a.oScroll.iBarWidth:i;if(r&&(d.scrollHeight>d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(g-a.oScroll.iBarWidth);d.style.width=q(g);a.nScrollHead.style.width=q(g);null!==a.nTFoot&&(a.nScrollFoot.style.width=q(g));""===a.oScroll.sX?D(a,1,"The table cannot fit into the current element which will cause column misalignment. The table has been drawn at its minimum possible width."): -""!==a.oScroll.sXInner&&D(a,1,"The table cannot fit into the current element which will cause column misalignment. Increase the sScrollXInner value or remove it to allow automatic calculation")}else d.style.width=q("100%"),a.nScrollHead.style.width=q("100%"),null!==a.nTFoot&&(a.nScrollFoot.style.width=q("100%"));""===a.oScroll.sY&&r&&(d.style.height=q(a.nTable.offsetHeight+a.oScroll.iBarWidth));""!==a.oScroll.sY&&a.oScroll.bCollapse&&(d.style.height=q(a.oScroll.sY),r=""!==a.oScroll.sX&&a.nTable.offsetWidth> -d.offsetWidth?a.oScroll.iBarWidth:0,a.nTable.offsetHeightd.clientHeight||"scroll"==h(d).css("overflow-y");b.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px";null!==a.nTFoot&&(R.style.width=q(r),l.style.width=q(r),l.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px");h(d).scroll();if(a.bSorted||a.bFiltered)d.scrollTop=0}function C(a,b,c){for(var d= -0,i=0,f=b.length,g,e;itd",b));j=N(a,f);for(f=d=0;fc)return null;if(null===a.aoData[c].nTr){var d=l.createElement("td");d.innerHTML=v(a,c,b,"");return d}return J(a,c)[b]}function Pa(a,b){for(var c=-1,d=-1,i=0;i/g,"");e.length>c&&(c=e.length,d=i)}return d}function q(a){if(null===a)return"0px";if("number"==typeof a)return 0>a?"0px":a+"px";var b=a.charCodeAt(a.length-1); -return 48>b||57/g,""),i=q[c].nTh,i.removeAttribute("aria-sort"),i.removeAttribute("aria-label"),q[c].bSortable?0d&&d++;f=RegExp(f+"[123]");var o;b=0;for(c=a.length;b
    ')[0];l.body.appendChild(b);a.oBrowser.bScrollOversize= -100===h("#DT_BrowserTest",b)[0].offsetWidth?!0:!1;l.body.removeChild(b)}function Va(a){return function(){var b=[s(this[j.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return j.ext.oApi[a].apply(this,b)}}var U=/\[.*?\]$/,Wa=X.JSON?JSON.stringify:function(a){var b=typeof a;if("object"!==b||null===a)return"string"===b&&(a='"'+a+'"'),a+"";var c,d,e=[],f=h.isArray(a);for(c in a)d=a[c],b=typeof d,"string"===b?d='"'+d+'"':"object"===b&&null!==d&&(d=Wa(d)),e.push((f?"":'"'+c+'":')+d);return(f? -"[":"{")+e+(f?"]":"}")};this.$=function(a,b){var c,d,e=[],f;d=s(this[j.ext.iApiIndex]);var g=d.aoData,o=d.aiDisplay,k=d.aiDisplayMaster;b||(b={});b=h.extend({},{filter:"none",order:"current",page:"all"},b);if("current"==b.page){c=d._iDisplayStart;for(d=d.fnDisplayEnd();c=d.fnRecordsDisplay()&&(d._iDisplayStart-=d._iDisplayLength,0>d._iDisplayStart&&(d._iDisplayStart=0));if(c===n||c)y(d),x(d);return g};this.fnDestroy=function(a){var b=s(this[j.ext.iApiIndex]),c=b.nTableWrapper.parentNode,d=b.nTBody,i,f,a=a===n?!1:a;b.bDestroying=!0;A(b,"aoDestroyCallback","destroy",[b]);if(!a){i=0;for(f=b.aoColumns.length;itr>td."+b.oClasses.sRowEmpty,b.nTable).parent().remove();b.nTable!=b.nTHead.parentNode&&(h(b.nTable).children("thead").remove(),b.nTable.appendChild(b.nTHead));b.nTFoot&&b.nTable!=b.nTFoot.parentNode&&(h(b.nTable).children("tfoot").remove(),b.nTable.appendChild(b.nTFoot));b.nTable.parentNode.removeChild(b.nTable);h(b.nTableWrapper).remove();b.aaSorting=[];b.aaSortingFixed=[];P(b);h(T(b)).removeClass(b.asStripeClasses.join(" "));h("th, td",b.nTHead).removeClass([b.oClasses.sSortable,b.oClasses.sSortableAsc, -b.oClasses.sSortableDesc,b.oClasses.sSortableNone].join(" "));b.bJUI&&(h("th span."+b.oClasses.sSortIcon+", td span."+b.oClasses.sSortIcon,b.nTHead).remove(),h("th, td",b.nTHead).each(function(){var a=h("div."+b.oClasses.sSortJUIWrapper,this),c=a.contents();h(this).append(c);a.remove()}));!a&&b.nTableReinsertBefore?c.insertBefore(b.nTable,b.nTableReinsertBefore):a||c.appendChild(b.nTable);i=0;for(f=b.aoData.length;i=t(d);if(!m)for(e=a;et<"F"ip>')):h.extend(g.oClasses,j.ext.oStdClasses);h(this).addClass(g.oClasses.sTable);if(""!==g.oScroll.sX||""!==g.oScroll.sY)g.oScroll.iBarWidth=Qa();g.iInitDisplayStart===n&&(g.iInitDisplayStart=e.iDisplayStart, -g._iDisplayStart=e.iDisplayStart);e.bStateSave&&(g.oFeatures.bStateSave=!0,Sa(g,e),z(g,"aoDrawCallback",ra,"state_save"));null!==e.iDeferLoading&&(g.bDeferLoading=!0,a=h.isArray(e.iDeferLoading),g._iRecordsDisplay=a?e.iDeferLoading[0]:e.iDeferLoading,g._iRecordsTotal=a?e.iDeferLoading[1]:e.iDeferLoading);null!==e.aaData&&(f=!0);""!==e.oLanguage.sUrl?(g.oLanguage.sUrl=e.oLanguage.sUrl,h.getJSON(g.oLanguage.sUrl,null,function(a){pa(a);h.extend(true,g.oLanguage,e.oLanguage,a);ba(g)}),i=!0):h.extend(!0, -g.oLanguage,e.oLanguage);null===e.asStripeClasses&&(g.asStripeClasses=[g.oClasses.sStripeOdd,g.oClasses.sStripeEven]);b=g.asStripeClasses.length;g.asDestroyStripes=[];if(b){c=!1;d=h(this).children("tbody").children("tr:lt("+b+")");for(a=0;a=g.aoColumns.length&&(g.aaSorting[a][0]=0);var k=g.aoColumns[g.aaSorting[a][0]];g.aaSorting[a][2]===n&&(g.aaSorting[a][2]=0);e.aaSorting===n&&g.saved_aaSorting===n&&(g.aaSorting[a][1]= -k.asSorting[0]);c=0;for(d=k.asSorting.length;c=parseInt(n,10)};j.fnIsDataTable=function(e){for(var h=j.settings,m=0;me)return e;for(var h=e+"",e=h.split(""),j="",h=h.length,k=0;k'+k.sPrevious+''+k.sNext+"":'';h(j).append(k);var l=h("a",j), -k=l[0],l=l[1];e.oApi._fnBindAction(k,{action:"previous"},n);e.oApi._fnBindAction(l,{action:"next"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_previous",l.id=e.sTableId+"_next",k.setAttribute("aria-controls",e.sTableId),l.setAttribute("aria-controls",e.sTableId))},fnUpdate:function(e){if(e.aanFeatures.p)for(var h=e.oClasses,j=e.aanFeatures.p,k,l=0,n=j.length;l'+k.sFirst+''+k.sPrevious+''+k.sNext+''+k.sLast+"");var t=h("a",j),k=t[0],l=t[1],r=t[2],t=t[3];e.oApi._fnBindAction(k,{action:"first"},n);e.oApi._fnBindAction(l,{action:"previous"},n);e.oApi._fnBindAction(r,{action:"next"},n);e.oApi._fnBindAction(t,{action:"last"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_first",l.id=e.sTableId+"_previous",r.id=e.sTableId+"_next",t.id=e.sTableId+"_last")}, -fnUpdate:function(e,o){if(e.aanFeatures.p){var m=j.ext.oPagination.iFullNumbersShowPages,k=Math.floor(m/2),l=Math.ceil(e.fnRecordsDisplay()/e._iDisplayLength),n=Math.ceil(e._iDisplayStart/e._iDisplayLength)+1,t="",r,B=e.oClasses,u,M=e.aanFeatures.p,L=function(h){e.oApi._fnBindAction(this,{page:h+r-1},function(h){e.oApi._fnPageChange(e,h.data.page);o(e);h.preventDefault()})};-1===e._iDisplayLength?n=k=r=1:l=l-k?(r=l-m+1,k=l):(r=n-Math.ceil(m/2)+1,k=r+m-1);for(m=r;m<=k;m++)t+= -n!==m?''+e.fnFormatNumber(m)+"":''+e.fnFormatNumber(m)+"";m=0;for(k=M.length;mh?1:0},"string-desc":function(e,h){return eh?-1:0},"html-pre":function(e){return e.replace(/<.*?>/g,"").toLowerCase()},"html-asc":function(e,h){return eh?1:0},"html-desc":function(e,h){return e< -h?1:e>h?-1:0},"date-pre":function(e){e=Date.parse(e);if(isNaN(e)||""===e)e=Date.parse("01/01/1970 00:00:00");return e},"date-asc":function(e,h){return e-h},"date-desc":function(e,h){return h-e},"numeric-pre":function(e){return"-"==e||""===e?0:1*e},"numeric-asc":function(e,h){return e-h},"numeric-desc":function(e,h){return h-e}});h.extend(j.ext.aTypes,[function(e){if("number"===typeof e)return"numeric";if("string"!==typeof e)return null;var h,j=!1;h=e.charAt(0);if(-1=="0123456789-".indexOf(h))return null; -for(var k=1;k")?"html":null}]);h.fn.DataTable=j;h.fn.dataTable=j;h.fn.dataTableSettings=j.settings;h.fn.dataTableExt=j.ext};"function"===typeof define&&define.amd?define(["jquery"],L):jQuery&&!jQuery.fn.dataTable&& -L(jQuery)})(window,document); +/* + * File: jquery.dataTables.min.js + * Version: 1.9.4 + * Author: Allan Jardine (www.sprymedia.co.uk) + * Info: www.datatables.net + * + * Copyright 2008-2012 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd + * + * This source file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + */ +(function(X,l,n){var L=function(h){var j=function(e){function o(a,b){var c=j.defaults.columns,d=a.aoColumns.length,c=h.extend({},j.models.oColumn,c,{sSortingClass:a.oClasses.sSortable,sSortingClassJUI:a.oClasses.sSortJUI,nTh:b?b:l.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.oDefaults:d});a.aoColumns.push(c);if(a.aoPreSearchCols[d]===n||null===a.aoPreSearchCols[d])a.aoPreSearchCols[d]=h.extend({},j.models.oSearch);else if(c=a.aoPreSearchCols[d], +c.bRegex===n&&(c.bRegex=!0),c.bSmart===n&&(c.bSmart=!0),c.bCaseInsensitive===n)c.bCaseInsensitive=!0;m(a,d,null)}function m(a,b,c){var d=a.aoColumns[b];c!==n&&null!==c&&(c.mDataProp&&!c.mData&&(c.mData=c.mDataProp),c.sType!==n&&(d.sType=c.sType,d._bAutoType=!1),h.extend(d,c),p(d,c,"sWidth","sWidthOrig"),c.iDataSort!==n&&(d.aDataSort=[c.iDataSort]),p(d,c,"aDataSort"));var i=d.mRender?Q(d.mRender):null,f=Q(d.mData);d.fnGetData=function(a,b){var c=f(a,b);return d.mRender&&b&&""!==b?i(c,b,a):c};d.fnSetData= +L(d.mData);a.oFeatures.bSort||(d.bSortable=!1);!d.bSortable||-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableNone,d.sSortingClassJUI=""):-1==h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortable,d.sSortingClassJUI=a.oClasses.sSortJUI):-1!=h.inArray("asc",d.asSorting)&&-1==h.inArray("desc",d.asSorting)?(d.sSortingClass=a.oClasses.sSortableAsc,d.sSortingClassJUI=a.oClasses.sSortJUIAscAllowed):-1== +h.inArray("asc",d.asSorting)&&-1!=h.inArray("desc",d.asSorting)&&(d.sSortingClass=a.oClasses.sSortableDesc,d.sSortingClassJUI=a.oClasses.sSortJUIDescAllowed)}function k(a){if(!1===a.oFeatures.bAutoWidth)return!1;da(a);for(var b=0,c=a.aoColumns.length;bj[f])d(a.aoColumns.length+j[f],b[i]);else if("string"===typeof j[f]){e=0;for(w=a.aoColumns.length;eb&&a[d]--; -1!=c&&a.splice(c,1)}function S(a,b,c){var d=a.aoColumns[c];return d.fnRender({iDataRow:b,iDataColumn:c,oSettings:a,aData:a.aoData[b]._aData,mDataProp:d.mData},v(a,b,c,"display"))}function ea(a,b){var c=a.aoData[b],d;if(null===c.nTr){c.nTr=l.createElement("tr");c.nTr._DT_RowIndex=b;c._aData.DT_RowId&&(c.nTr.id=c._aData.DT_RowId);c._aData.DT_RowClass&& +(c.nTr.className=c._aData.DT_RowClass);for(var i=0,f=a.aoColumns.length;i=a.fnRecordsDisplay()?0:a.iInitDisplayStart,a.iInitDisplayStart=-1,y(a));if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++;else if(a.oFeatures.bServerSide){if(!a.bDestroying&&!wa(a))return}else a.iDraw++;if(0!==a.aiDisplay.length){var g= +a._iDisplayStart;d=a._iDisplayEnd;a.oFeatures.bServerSide&&(g=0,d=a.aoData.length);for(;g")[0];a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=h('
    ')[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var c=a.nTableWrapper,d=a.sDom.split(""),i,f,g,e,w,o,k,m=0;m")[0];w=d[m+ +1];if("'"==w||'"'==w){o="";for(k=2;d[m+k]!=w;)o+=d[m+k],k++;"H"==o?o=a.oClasses.sJUIHeader:"F"==o&&(o=a.oClasses.sJUIFooter);-1!=o.indexOf(".")?(w=o.split("."),e.id=w[0].substr(1,w[0].length-1),e.className=w[1]):"#"==o.charAt(0)?e.id=o.substr(1,o.length-1):e.className=o;m+=k}c.appendChild(e);c=e}else if(">"==g)c=c.parentNode;else if("l"==g&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange)i=ya(a),f=1;else if("f"==g&&a.oFeatures.bFilter)i=za(a),f=1;else if("r"==g&&a.oFeatures.bProcessing)i=Aa(a),f= +1;else if("t"==g)i=Ba(a),f=1;else if("i"==g&&a.oFeatures.bInfo)i=Ca(a),f=1;else if("p"==g&&a.oFeatures.bPaginate)i=Da(a),f=1;else if(0!==j.ext.aoFeatures.length){e=j.ext.aoFeatures;k=0;for(w=e.length;k'):""===c?'':c+' ',d=l.createElement("div");d.className=a.oClasses.sFilter;d.innerHTML="";a.aanFeatures.f||(d.id=a.sTableId+"_filter");c=h('input[type="text"]',d);d._DT_Input=c[0];c.val(b.sSearch.replace('"',"""));c.bind("keyup.DT",function(){for(var c=a.aanFeatures.f,d=this.value===""?"":this.value, +g=0,e=c.length;g=b.length)a.aiDisplay.splice(0,a.aiDisplay.length),a.aiDisplay=a.aiDisplayMaster.slice();else if(a.aiDisplay.length==a.aiDisplayMaster.length||i.sSearch.length>b.length||1==c||0!==b.indexOf(i.sSearch)){a.aiDisplay.splice(0, +a.aiDisplay.length);la(a,1);for(b=0;b").html(c).text()); +return c.replace(/[\n\r]/g," ")}function ma(a,b,c,d){if(c)return a=b?a.split(" "):oa(a).split(" "),a="^(?=.*?"+a.join(")(?=.*?")+").*$",RegExp(a,d?"i":"");a=b?a:oa(a);return RegExp(a,d?"i":"")}function Ja(a,b){return"function"===typeof j.ext.ofnSearch[b]?j.ext.ofnSearch[b](a):null===a?"":"html"==b?a.replace(/[\r\n]/g," ").replace(/<.*?>/g,""):"string"===typeof a?a.replace(/[\r\n]/g," "):a}function oa(a){return a.replace(RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"), +"\\$1")}function Ca(a){var b=l.createElement("div");b.className=a.oClasses.sInfo;a.aanFeatures.i||(a.aoDrawCallback.push({fn:Ka,sName:"information"}),b.id=a.sTableId+"_info");a.nTable.setAttribute("aria-describedby",a.sTableId+"_info");return b}function Ka(a){if(a.oFeatures.bInfo&&0!==a.aanFeatures.i.length){var b=a.oLanguage,c=a._iDisplayStart+1,d=a.fnDisplayEnd(),i=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),g;g=0===f?b.sInfoEmpty:b.sInfo;f!=i&&(g+=" "+b.sInfoFiltered);g+=b.sInfoPostFix;g=ja(a,g); +null!==b.fnInfoCallback&&(g=b.fnInfoCallback.call(a.oInstance,a,c,d,i,f,g));a=a.aanFeatures.i;b=0;for(c=a.length;b",c,d,i=a.aLengthMenu;if(2==i.length&&"object"===typeof i[0]&&"object"===typeof i[1]){c=0;for(d=i[0].length;c'+i[1][c]+""}else{c=0;for(d=i.length;c'+i[c]+""}b+="";i=l.createElement("div");a.aanFeatures.l|| +(i.id=a.sTableId+"_length");i.className=a.oClasses.sLength;i.innerHTML="";h('select option[value="'+a._iDisplayLength+'"]',i).attr("selected",!0);h("select",i).bind("change.DT",function(){var b=h(this).val(),i=a.aanFeatures.l;c=0;for(d=i.length;ca.aiDisplay.length||-1==a._iDisplayLength?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Da(a){if(a.oScroll.bInfinite)return null;var b=l.createElement("div");b.className=a.oClasses.sPaging+a.sPaginationType;j.ext.oPagination[a.sPaginationType].fnInit(a, +b,function(a){y(a);x(a)});a.aanFeatures.p||a.aoDrawCallback.push({fn:function(a){j.ext.oPagination[a.sPaginationType].fnUpdate(a,function(a){y(a);x(a)})},sName:"pagination"});return b}function qa(a,b){var c=a._iDisplayStart;if("number"===typeof b)a._iDisplayStart=b*a._iDisplayLength,a._iDisplayStart>a.fnRecordsDisplay()&&(a._iDisplayStart=0);else if("first"==b)a._iDisplayStart=0;else if("previous"==b)a._iDisplayStart=0<=a._iDisplayLength?a._iDisplayStart-a._iDisplayLength:0,0>a._iDisplayStart&&(a._iDisplayStart= +0);else if("next"==b)0<=a._iDisplayLength?a._iDisplayStart+a._iDisplayLengthh(a.nTable).height()-a.oScroll.iLoadGap&&a.fnDisplayEnd()d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(h(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else""!==a.oScroll.sXInner?a.nTable.style.width= +q(a.oScroll.sXInner):i==h(d).width()&&h(d).height()i-a.oScroll.iBarWidth&&(a.nTable.style.width=q(i))):a.nTable.style.width=q(i);i=h(a.nTable).outerWidth();C(s,e);C(function(a){p.push(q(h(a).width()))},e);C(function(a,b){a.style.width=p[b]},g);h(e).height(0);null!==a.nTFoot&&(C(s,j),C(function(a){n.push(q(h(a).width()))},j),C(function(a,b){a.style.width=n[b]},o),h(j).height(0));C(function(a,b){a.innerHTML= +"";a.style.width=p[b]},e);null!==a.nTFoot&&C(function(a,b){a.innerHTML="";a.style.width=n[b]},j);if(h(a.nTable).outerWidth()d.offsetHeight||"scroll"==h(d).css("overflow-y")?i+a.oScroll.iBarWidth:i;if(r&&(d.scrollHeight>d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(g-a.oScroll.iBarWidth);d.style.width=q(g);a.nScrollHead.style.width=q(g);null!==a.nTFoot&&(a.nScrollFoot.style.width=q(g));""===a.oScroll.sX?D(a,1,"The table cannot fit into the current element which will cause column misalignment. The table has been drawn at its minimum possible width."): +""!==a.oScroll.sXInner&&D(a,1,"The table cannot fit into the current element which will cause column misalignment. Increase the sScrollXInner value or remove it to allow automatic calculation")}else d.style.width=q("100%"),a.nScrollHead.style.width=q("100%"),null!==a.nTFoot&&(a.nScrollFoot.style.width=q("100%"));""===a.oScroll.sY&&r&&(d.style.height=q(a.nTable.offsetHeight+a.oScroll.iBarWidth));""!==a.oScroll.sY&&a.oScroll.bCollapse&&(d.style.height=q(a.oScroll.sY),r=""!==a.oScroll.sX&&a.nTable.offsetWidth> +d.offsetWidth?a.oScroll.iBarWidth:0,a.nTable.offsetHeightd.clientHeight||"scroll"==h(d).css("overflow-y");b.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px";null!==a.nTFoot&&(R.style.width=q(r),l.style.width=q(r),l.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px");h(d).scroll();if(a.bSorted||a.bFiltered)d.scrollTop=0}function C(a,b,c){for(var d= +0,i=0,f=b.length,g,e;itd",b));j=N(a,f);for(f=d=0;fc)return null;if(null===a.aoData[c].nTr){var d=l.createElement("td");d.innerHTML=v(a,c,b,"");return d}return J(a,c)[b]}function Pa(a,b){for(var c=-1,d=-1,i=0;i/g,"");e.length>c&&(c=e.length,d=i)}return d}function q(a){if(null===a)return"0px";if("number"==typeof a)return 0>a?"0px":a+"px";var b=a.charCodeAt(a.length-1); +return 48>b||57/g,""),i=q[c].nTh,i.removeAttribute("aria-sort"),i.removeAttribute("aria-label"),q[c].bSortable?0d&&d++;f=RegExp(f+"[123]");var o;b=0;for(c=a.length;b
    ')[0];l.body.appendChild(b);a.oBrowser.bScrollOversize= +100===h("#DT_BrowserTest",b)[0].offsetWidth?!0:!1;l.body.removeChild(b)}function Va(a){return function(){var b=[s(this[j.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return j.ext.oApi[a].apply(this,b)}}var U=/\[.*?\]$/,Wa=X.JSON?JSON.stringify:function(a){var b=typeof a;if("object"!==b||null===a)return"string"===b&&(a='"'+a+'"'),a+"";var c,d,e=[],f=h.isArray(a);for(c in a)d=a[c],b=typeof d,"string"===b?d='"'+d+'"':"object"===b&&null!==d&&(d=Wa(d)),e.push((f?"":'"'+c+'":')+d);return(f? +"[":"{")+e+(f?"]":"}")};this.$=function(a,b){var c,d,e=[],f;d=s(this[j.ext.iApiIndex]);var g=d.aoData,o=d.aiDisplay,k=d.aiDisplayMaster;b||(b={});b=h.extend({},{filter:"none",order:"current",page:"all"},b);if("current"==b.page){c=d._iDisplayStart;for(d=d.fnDisplayEnd();c=d.fnRecordsDisplay()&&(d._iDisplayStart-=d._iDisplayLength,0>d._iDisplayStart&&(d._iDisplayStart=0));if(c===n||c)y(d),x(d);return g};this.fnDestroy=function(a){var b=s(this[j.ext.iApiIndex]),c=b.nTableWrapper.parentNode,d=b.nTBody,i,f,a=a===n?!1:a;b.bDestroying=!0;A(b,"aoDestroyCallback","destroy",[b]);if(!a){i=0;for(f=b.aoColumns.length;itr>td."+b.oClasses.sRowEmpty,b.nTable).parent().remove();b.nTable!=b.nTHead.parentNode&&(h(b.nTable).children("thead").remove(),b.nTable.appendChild(b.nTHead));b.nTFoot&&b.nTable!=b.nTFoot.parentNode&&(h(b.nTable).children("tfoot").remove(),b.nTable.appendChild(b.nTFoot));b.nTable.parentNode.removeChild(b.nTable);h(b.nTableWrapper).remove();b.aaSorting=[];b.aaSortingFixed=[];P(b);h(T(b)).removeClass(b.asStripeClasses.join(" "));h("th, td",b.nTHead).removeClass([b.oClasses.sSortable,b.oClasses.sSortableAsc, +b.oClasses.sSortableDesc,b.oClasses.sSortableNone].join(" "));b.bJUI&&(h("th span."+b.oClasses.sSortIcon+", td span."+b.oClasses.sSortIcon,b.nTHead).remove(),h("th, td",b.nTHead).each(function(){var a=h("div."+b.oClasses.sSortJUIWrapper,this),c=a.contents();h(this).append(c);a.remove()}));!a&&b.nTableReinsertBefore?c.insertBefore(b.nTable,b.nTableReinsertBefore):a||c.appendChild(b.nTable);i=0;for(f=b.aoData.length;i=t(d);if(!m)for(e=a;et<"F"ip>')):h.extend(g.oClasses,j.ext.oStdClasses);h(this).addClass(g.oClasses.sTable);if(""!==g.oScroll.sX||""!==g.oScroll.sY)g.oScroll.iBarWidth=Qa();g.iInitDisplayStart===n&&(g.iInitDisplayStart=e.iDisplayStart, +g._iDisplayStart=e.iDisplayStart);e.bStateSave&&(g.oFeatures.bStateSave=!0,Sa(g,e),z(g,"aoDrawCallback",ra,"state_save"));null!==e.iDeferLoading&&(g.bDeferLoading=!0,a=h.isArray(e.iDeferLoading),g._iRecordsDisplay=a?e.iDeferLoading[0]:e.iDeferLoading,g._iRecordsTotal=a?e.iDeferLoading[1]:e.iDeferLoading);null!==e.aaData&&(f=!0);""!==e.oLanguage.sUrl?(g.oLanguage.sUrl=e.oLanguage.sUrl,h.getJSON(g.oLanguage.sUrl,null,function(a){pa(a);h.extend(true,g.oLanguage,e.oLanguage,a);ba(g)}),i=!0):h.extend(!0, +g.oLanguage,e.oLanguage);null===e.asStripeClasses&&(g.asStripeClasses=[g.oClasses.sStripeOdd,g.oClasses.sStripeEven]);b=g.asStripeClasses.length;g.asDestroyStripes=[];if(b){c=!1;d=h(this).children("tbody").children("tr:lt("+b+")");for(a=0;a=g.aoColumns.length&&(g.aaSorting[a][0]=0);var k=g.aoColumns[g.aaSorting[a][0]];g.aaSorting[a][2]===n&&(g.aaSorting[a][2]=0);e.aaSorting===n&&g.saved_aaSorting===n&&(g.aaSorting[a][1]= +k.asSorting[0]);c=0;for(d=k.asSorting.length;c=parseInt(n,10)};j.fnIsDataTable=function(e){for(var h=j.settings,m=0;me)return e;for(var h=e+"",e=h.split(""),j="",h=h.length,k=0;k'+k.sPrevious+''+k.sNext+"":'';h(j).append(k);var l=h("a",j), +k=l[0],l=l[1];e.oApi._fnBindAction(k,{action:"previous"},n);e.oApi._fnBindAction(l,{action:"next"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_previous",l.id=e.sTableId+"_next",k.setAttribute("aria-controls",e.sTableId),l.setAttribute("aria-controls",e.sTableId))},fnUpdate:function(e){if(e.aanFeatures.p)for(var h=e.oClasses,j=e.aanFeatures.p,k,l=0,n=j.length;l'+k.sFirst+''+k.sPrevious+''+k.sNext+''+k.sLast+"");var t=h("a",j),k=t[0],l=t[1],r=t[2],t=t[3];e.oApi._fnBindAction(k,{action:"first"},n);e.oApi._fnBindAction(l,{action:"previous"},n);e.oApi._fnBindAction(r,{action:"next"},n);e.oApi._fnBindAction(t,{action:"last"},n);e.aanFeatures.p||(j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_first",l.id=e.sTableId+"_previous",r.id=e.sTableId+"_next",t.id=e.sTableId+"_last")}, +fnUpdate:function(e,o){if(e.aanFeatures.p){var m=j.ext.oPagination.iFullNumbersShowPages,k=Math.floor(m/2),l=Math.ceil(e.fnRecordsDisplay()/e._iDisplayLength),n=Math.ceil(e._iDisplayStart/e._iDisplayLength)+1,t="",r,B=e.oClasses,u,M=e.aanFeatures.p,L=function(h){e.oApi._fnBindAction(this,{page:h+r-1},function(h){e.oApi._fnPageChange(e,h.data.page);o(e);h.preventDefault()})};-1===e._iDisplayLength?n=k=r=1:l=l-k?(r=l-m+1,k=l):(r=n-Math.ceil(m/2)+1,k=r+m-1);for(m=r;m<=k;m++)t+= +n!==m?''+e.fnFormatNumber(m)+"":''+e.fnFormatNumber(m)+"";m=0;for(k=M.length;mh?1:0},"string-desc":function(e,h){return eh?-1:0},"html-pre":function(e){return e.replace(/<.*?>/g,"").toLowerCase()},"html-asc":function(e,h){return eh?1:0},"html-desc":function(e,h){return e< +h?1:e>h?-1:0},"date-pre":function(e){e=Date.parse(e);if(isNaN(e)||""===e)e=Date.parse("01/01/1970 00:00:00");return e},"date-asc":function(e,h){return e-h},"date-desc":function(e,h){return h-e},"numeric-pre":function(e){return"-"==e||""===e?0:1*e},"numeric-asc":function(e,h){return e-h},"numeric-desc":function(e,h){return h-e}});h.extend(j.ext.aTypes,[function(e){if("number"===typeof e)return"numeric";if("string"!==typeof e)return null;var h,j=!1;h=e.charAt(0);if(-1=="0123456789-".indexOf(h))return null; +for(var k=1;k")?"html":null}]);h.fn.DataTable=j;h.fn.dataTable=j;h.fn.dataTableSettings=j.settings;h.fn.dataTableExt=j.ext};"function"===typeof define&&define.amd?define(["jquery"],L):jQuery&&!jQuery.fn.dataTable&& +L(jQuery)})(window,document); diff --git a/openo-portal/portal-common/src/main/webapp/common/thirdparty/data-tables/jquery.dataTables.js b/openo-portal/portal-common/src/main/webapp/common/thirdparty/data-tables/jquery.dataTables.js index 380ab1e4..5e2808c2 100644 --- a/openo-portal/portal-common/src/main/webapp/common/thirdparty/data-tables/jquery.dataTables.js +++ b/openo-portal/portal-common/src/main/webapp/common/thirdparty/data-tables/jquery.dataTables.js @@ -1,15268 +1,15268 @@ -/*! DataTables 1.10.11 - * ©2008-2015 SpryMedia Ltd - datatables.net/license - */ - -/** - * @summary DataTables - * @description Paginate, search and order HTML tables - * @version 1.10.11 - * @file jquery.dataTables.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2008-2015 SpryMedia Ltd. - * - * This source file is free software, available under the following license: - * MIT license - http://datatables.net/license - * - * This source file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. - * - * For details please refer to: http://www.datatables.net - */ - -/*jslint evil: true, undef: true, browser: true */ -/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ - -(function( factory ) { - "use strict"; - - if ( typeof define === 'function' && define.amd ) { - // AMD - define( ['jquery'], function ( $ ) { - return factory( $, window, document ); - } ); - } - else if ( typeof exports === 'object' ) { - // CommonJS - module.exports = function (root, $) { - if ( ! root ) { - // CommonJS environments without a window global must pass a - // root. This will give an error otherwise - root = window; - } - - if ( ! $ ) { - $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window - require('jquery') : - require('jquery')( root ); - } - - return factory( $, root, root.document ); - }; - } - else { - // Browser - factory( jQuery, window, document ); - } -} -(function( $, window, document, undefined ) { - "use strict"; - - /** - * DataTables is a plug-in for the jQuery Javascript library. It is a highly - * flexible tool, based upon the foundations of progressive enhancement, - * which will add advanced interaction controls to any HTML table. For a - * full list of features please refer to - * [DataTables.net](href="http://datatables.net). - * - * Note that the `DataTable` object is not a global variable but is aliased - * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may - * be accessed. - * - * @class - * @param {object} [init={}] Configuration object for DataTables. Options - * are defined by {@link DataTable.defaults} - * @requires jQuery 1.7+ - * - * @example - * // Basic initialisation - * $(document).ready( function { - * $('#example').dataTable(); - * } ); - * - * @example - * // Initialisation with configuration options - in this case, disable - * // pagination and sorting. - * $(document).ready( function { - * $('#example').dataTable( { - * "paginate": false, - * "sort": false - * } ); - * } ); - */ - var DataTable; - - - /* - * It is useful to have variables which are scoped locally so only the - * DataTables functions can access them and they don't leak into global space. - * At the same time these functions are often useful over multiple files in the - * core and API, so we list, or at least document, all variables which are used - * by DataTables as private variables here. This also ensures that there is no - * clashing of variable names and that they can easily referenced for reuse. - */ - - - // Defined else where - // _selector_run - // _selector_opts - // _selector_first - // _selector_row_indexes - - var _ext; // DataTable.ext - var _Api; // DataTable.Api - var _api_register; // DataTable.Api.register - var _api_registerPlural; // DataTable.Api.registerPlural - - var _re_dic = {}; - var _re_new_lines = /[\r\n]/g; - var _re_html = /<.*?>/g; - var _re_date_start = /^[\w\+\-]/; - var _re_date_end = /[\w\+\-]$/; - - // Escape regular expression special characters - var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); - - // http://en.wikipedia.org/wiki/Foreign_exchange_market - // - \u20BD - Russian ruble. - // - \u20a9 - South Korean Won - // - \u20BA - Turkish Lira - // - \u20B9 - Indian Rupee - // - R - Brazil (R$) and South Africa - // - fr - Swiss Franc - // - kr - Swedish krona, Norwegian krone and Danish krone - // - \u2009 is thin space and \u202F is narrow no-break space, both used in many - // standards as thousands separators. - var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi; - - - var _empty = function ( d ) { - return !d || d === true || d === '-' ? true : false; - }; - - - var _intVal = function ( s ) { - var integer = parseInt( s, 10 ); - return !isNaN(integer) && isFinite(s) ? integer : null; - }; - - // Convert from a formatted number with characters other than `.` as the - // decimal place, to a Javascript number - var _numToDecimal = function ( num, decimalPoint ) { - // Cache created regular expressions for speed as this function is called often - if ( ! _re_dic[ decimalPoint ] ) { - _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); - } - return typeof num === 'string' && decimalPoint !== '.' ? - num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : - num; - }; - - - var _isNumber = function ( d, decimalPoint, formatted ) { - var strType = typeof d === 'string'; - - // If empty return immediately so there must be a number if it is a - // formatted string (this stops the string "k", or "kr", etc being detected - // as a formatted number for currency - if ( _empty( d ) ) { - return true; - } - - if ( decimalPoint && strType ) { - d = _numToDecimal( d, decimalPoint ); - } - - if ( formatted && strType ) { - d = d.replace( _re_formatted_numeric, '' ); - } - - return !isNaN( parseFloat(d) ) && isFinite( d ); - }; - - - // A string without HTML in it can be considered to be HTML still - var _isHtml = function ( d ) { - return _empty( d ) || typeof d === 'string'; - }; - - - var _htmlNumeric = function ( d, decimalPoint, formatted ) { - if ( _empty( d ) ) { - return true; - } - - var html = _isHtml( d ); - return ! html ? - null : - _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? - true : - null; - }; - - - var _pluck = function ( a, prop, prop2 ) { - var out = []; - var i=0, ien=a.length; - - // Could have the test in the loop for slightly smaller code, but speed - // is essential here - if ( prop2 !== undefined ) { - for ( ; i') - .css( { - position: 'fixed', - top: 0, - left: 0, - height: 1, - width: 1, - overflow: 'hidden' - } ) - .append( - $('
    ') - .css( { - position: 'absolute', - top: 1, - left: 1, - width: 100, - overflow: 'scroll' - } ) - .append( - $('
    ') - .css( { - width: '100%', - height: 10 - } ) - ) - ) - .appendTo( 'body' ); - - var outer = n.children(); - var inner = outer.children(); - - // Numbers below, in order, are: - // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth - // - // IE6 XP: 100 100 100 83 - // IE7 Vista: 100 100 100 83 - // IE 8+ Windows: 83 83 100 83 - // Evergreen Windows: 83 83 100 83 - // Evergreen Mac with scrollbars: 85 85 100 85 - // Evergreen Mac without scrollbars: 100 100 100 100 - - // Get scrollbar width - browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth; - - // IE6/7 will oversize a width 100% element inside a scrolling element, to - // include the width of the scrollbar, while other browsers ensure the inner - // element is contained without forcing scrolling - browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100; - - // In rtl text layout, some browsers (most, but not all) will place the - // scrollbar on the left, rather than the right. - browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1; - - // IE8- don't provide height and width for getBoundingClientRect - browser.bBounding = n[0].getBoundingClientRect().width ? true : false; - - n.remove(); - } - - $.extend( settings.oBrowser, DataTable.__browser ); - settings.oScroll.iBarWidth = DataTable.__browser.barWidth; - } - - - /** - * Array.prototype reduce[Right] method, used for browsers which don't support - * JS 1.6. Done this way to reduce code size, since we iterate either way - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnReduce ( that, fn, init, start, end, inc ) - { - var - i = start, - value, - isSet = false; - - if ( init !== undefined ) { - value = init; - isSet = true; - } - - while ( i !== end ) { - if ( ! that.hasOwnProperty(i) ) { - continue; - } - - value = isSet ? - fn( value, that[i], i, that ) : - that[i]; - - isSet = true; - i += inc; - } - - return value; - } - - /** - * Add a column to the list used for the table with default values - * @param {object} oSettings dataTables settings object - * @param {node} nTh The th element for this column - * @memberof DataTable#oApi - */ - function _fnAddColumn( oSettings, nTh ) - { - // Add column to aoColumns array - var oDefaults = DataTable.defaults.column; - var iCol = oSettings.aoColumns.length; - var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { - "nTh": nTh ? nTh : document.createElement('th'), - "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', - "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], - "mData": oDefaults.mData ? oDefaults.mData : iCol, - idx: iCol - } ); - oSettings.aoColumns.push( oCol ); - - // Add search object for column specific search. Note that the `searchCols[ iCol ]` - // passed into extend can be undefined. This allows the user to give a default - // with only some of the parameters defined, and also not give a default - var searchCols = oSettings.aoPreSearchCols; - searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); - - // Use the default column options function to initialise classes etc - _fnColumnOptions( oSettings, iCol, $(nTh).data() ); - } - - - /** - * Apply options for a column - * @param {object} oSettings dataTables settings object - * @param {int} iCol column index to consider - * @param {object} oOptions object with sType, bVisible and bSearchable etc - * @memberof DataTable#oApi - */ - function _fnColumnOptions( oSettings, iCol, oOptions ) - { - var oCol = oSettings.aoColumns[ iCol ]; - var oClasses = oSettings.oClasses; - var th = $(oCol.nTh); - - // Try to get width information from the DOM. We can't get it from CSS - // as we'd need to parse the CSS stylesheet. `width` option can override - if ( ! oCol.sWidthOrig ) { - // Width attribute - oCol.sWidthOrig = th.attr('width') || null; - - // Style attribute - var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); - if ( t ) { - oCol.sWidthOrig = t[1]; - } - } - - /* User specified column options */ - if ( oOptions !== undefined && oOptions !== null ) - { - // Backwards compatibility - _fnCompatCols( oOptions ); - - // Map camel case parameters to their Hungarian counterparts - _fnCamelToHungarian( DataTable.defaults.column, oOptions ); - - /* Backwards compatibility for mDataProp */ - if ( oOptions.mDataProp !== undefined && !oOptions.mData ) - { - oOptions.mData = oOptions.mDataProp; - } - - if ( oOptions.sType ) - { - oCol._sManualType = oOptions.sType; - } - - // `class` is a reserved word in Javascript, so we need to provide - // the ability to use a valid name for the camel case input - if ( oOptions.className && ! oOptions.sClass ) - { - oOptions.sClass = oOptions.className; - } - - $.extend( oCol, oOptions ); - _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); - - /* iDataSort to be applied (backwards compatibility), but aDataSort will take - * priority if defined - */ - if ( oOptions.iDataSort !== undefined ) - { - oCol.aDataSort = [ oOptions.iDataSort ]; - } - _fnMap( oCol, oOptions, "aDataSort" ); - } - - /* Cache the data get and set functions for speed */ - var mDataSrc = oCol.mData; - var mData = _fnGetObjectDataFn( mDataSrc ); - var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; - - var attrTest = function( src ) { - return typeof src === 'string' && src.indexOf('@') !== -1; - }; - oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( - attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) - ); - oCol._setter = null; - - oCol.fnGetData = function (rowData, type, meta) { - var innerData = mData( rowData, type, undefined, meta ); - - return mRender && type ? - mRender( innerData, type, rowData, meta ) : - innerData; - }; - oCol.fnSetData = function ( rowData, val, meta ) { - return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); - }; - - // Indicate if DataTables should read DOM data as an object or array - // Used in _fnGetRowElements - if ( typeof mDataSrc !== 'number' ) { - oSettings._rowReadObject = true; - } - - /* Feature sorting overrides column specific when off */ - if ( !oSettings.oFeatures.bSort ) - { - oCol.bSortable = false; - th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called - } - - /* Check that the class assignment is correct for sorting */ - var bAsc = $.inArray('asc', oCol.asSorting) !== -1; - var bDesc = $.inArray('desc', oCol.asSorting) !== -1; - if ( !oCol.bSortable || (!bAsc && !bDesc) ) - { - oCol.sSortingClass = oClasses.sSortableNone; - oCol.sSortingClassJUI = ""; - } - else if ( bAsc && !bDesc ) - { - oCol.sSortingClass = oClasses.sSortableAsc; - oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; - } - else if ( !bAsc && bDesc ) - { - oCol.sSortingClass = oClasses.sSortableDesc; - oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; - } - else - { - oCol.sSortingClass = oClasses.sSortable; - oCol.sSortingClassJUI = oClasses.sSortJUI; - } - } - - - /** - * Adjust the table column widths for new data. Note: you would probably want to - * do a redraw after calling this function! - * @param {object} settings dataTables settings object - * @memberof DataTable#oApi - */ - function _fnAdjustColumnSizing ( settings ) - { - /* Not interested in doing column width calculation if auto-width is disabled */ - if ( settings.oFeatures.bAutoWidth !== false ) - { - var columns = settings.aoColumns; - - _fnCalculateColumnWidths( settings ); - for ( var i=0 , iLen=columns.length ; i