public inbox for [email protected]
help / color / mirror / Atom feedIssue with SlickGrid
9+ messages / 4 participants
[nested] [flat]
* Issue with SlickGrid
@ 2017-04-26 20:53 Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 06:39 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
0 siblings, 1 reply; 9+ messages in thread
From: Joao Pedro De Almeida Pereira @ 2017-04-26 20:53 UTC (permalink / raw)
To: pgadmin-hackers
Hello Hackers,
While doing some changes to the Query Results we found out that there was a
issue with Slick grid.
The issue that we found was with the CellSelectModel, behaved differently
when pressing Ctrl and Command(Mac). We created a PR
<https://github.com/6pac/SlickGrid/pull/100; with the change to changes the
behavior of the plugin.
When this PR is applied to the SlickGrid library we need to apply it to the
current version of SlickGrid that we have vendorized.
According to the libraries.txt file we are in version 2.2.4 of the library
but a diff between our code and the libraries version 2.2.4 shows
differences in the code.
Did we do any change to SlickGrid library that is vendorized? Or is just
the information in libraries.txt that is incorrect?
Does anyone know any problem if we bump the version of SlickGrid to the
newer version after the PR is applied?
Thanks
Joao
^ permalink raw reply [nested|flat] 9+ messages in thread
* Re: Issue with SlickGrid
2017-04-26 20:53 Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
@ 2017-04-27 06:39 ` Murtuza Zabuawala <[email protected]>
2017-04-27 06:46 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
0 siblings, 1 reply; 9+ messages in thread
From: Murtuza Zabuawala @ 2017-04-27 06:39 UTC (permalink / raw)
To: Joao Pedro De Almeida Pereira <[email protected]>; +Cc: pgadmin-hackers
Hello Joao,
Yes, We made some changes in SlickGrid library when we integrated it into
Query tool.
*Issue:* Last row from the query result set was not displaying correctly in
query tool when we have scrollbar in grid.
The row hight/width pixel size calculations is done inside SlickGrid
javascript code, Though we tried solve it through CSS but we had no luck,
so we had no other choice but to do it in library it self.
The changes were,
1) "getDataLengthIncludingAddNew()" function (slick.grid.js) to add two new
rows instead of one when user add values into row (one row is dummy & not
visible to user so that it displays last row correctly)
2) Other change was done into "appendRowHtml()" function to calculating the
correct number of rows in SlickGrid result as we have added our own custom
row as mentioned earlier.
3) Abbreviated long CSS classes as mentioed in README file.
Apologies we missed to update this change in README.
--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Thu, Apr 27, 2017 at 2:23 AM, Joao Pedro De Almeida Pereira <
[email protected]> wrote:
> Hello Hackers,
>
> While doing some changes to the Query Results we found out that there was
> a issue with Slick grid.
>
> The issue that we found was with the CellSelectModel, behaved differently
> when pressing Ctrl and Command(Mac). We created a PR
> <https://github.com/6pac/SlickGrid/pull/100; with the change to changes
> the behavior of the plugin.
>
> When this PR is applied to the SlickGrid library we need to apply it to
> the current version of SlickGrid that we have vendorized.
> According to the libraries.txt file we are in version 2.2.4 of the library
> but a diff between our code and the libraries version 2.2.4 shows
> differences in the code.
>
> Did we do any change to SlickGrid library that is vendorized? Or is just
> the information in libraries.txt that is incorrect?
> Does anyone know any problem if we bump the version of SlickGrid to the
> newer version after the PR is applied?
>
> Thanks
> Joao
>
^ permalink raw reply [nested|flat] 9+ messages in thread
* Re: Issue with SlickGrid
2017-04-26 20:53 Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 06:39 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
@ 2017-04-27 06:46 ` Murtuza Zabuawala <[email protected]>
2017-04-27 11:12 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
0 siblings, 1 reply; 9+ messages in thread
From: Murtuza Zabuawala @ 2017-04-27 06:46 UTC (permalink / raw)
To: Joao Pedro De Almeida Pereira <[email protected]>; +Cc: pgadmin-hackers
+++
Reference:
https://www.postgresql.org/message-id/CAKKotZRjqbKAZev81Zk78nikDVXqLKEDV5r%2BsW8Me31Gpzrm_A%40mail.g...
--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Thu, Apr 27, 2017 at 12:09 PM, Murtuza Zabuawala <
[email protected]> wrote:
> Hello Joao,
>
> Yes, We made some changes in SlickGrid library when we integrated it into
> Query tool.
>
> *Issue:* Last row from the query result set was not displaying correctly
> in query tool when we have scrollbar in grid.
>
> The row hight/width pixel size calculations is done inside SlickGrid
> javascript code, Though we tried solve it through CSS but we had no luck,
> so we had no other choice but to do it in library it self.
>
> The changes were,
> 1) "getDataLengthIncludingAddNew()" function (slick.grid.js) to add two
> new rows instead of one when user add values into row (one row is dummy &
> not visible to user so that it displays last row correctly)
> 2) Other change was done into "appendRowHtml()" function to calculating
> the correct number of rows in SlickGrid result as we have added our own
> custom row as mentioned earlier.
> 3) Abbreviated long CSS classes as mentioed in README file.
>
> Apologies we missed to update this change in README.
>
>
> --
> Regards,
> Murtuza Zabuawala
> EnterpriseDB: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
> On Thu, Apr 27, 2017 at 2:23 AM, Joao Pedro De Almeida Pereira <
> [email protected]> wrote:
>
>> Hello Hackers,
>>
>> While doing some changes to the Query Results we found out that there was
>> a issue with Slick grid.
>>
>> The issue that we found was with the CellSelectModel, behaved differently
>> when pressing Ctrl and Command(Mac). We created a PR
>> <https://github.com/6pac/SlickGrid/pull/100; with the change to changes
>> the behavior of the plugin.
>>
>> When this PR is applied to the SlickGrid library we need to apply it to
>> the current version of SlickGrid that we have vendorized.
>> According to the libraries.txt file we are in version 2.2.4 of the
>> library but a diff between our code and the libraries version 2.2.4 shows
>> differences in the code.
>>
>> Did we do any change to SlickGrid library that is vendorized? Or is just
>> the information in libraries.txt that is incorrect?
>> Does anyone know any problem if we bump the version of SlickGrid to the
>> newer version after the PR is applied?
>>
>> Thanks
>> Joao
>>
>
>
^ permalink raw reply [nested|flat] 9+ messages in thread
* Re: Issue with SlickGrid
2017-04-26 20:53 Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 06:39 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 06:46 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
@ 2017-04-27 11:12 ` Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 12:13 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
0 siblings, 1 reply; 9+ messages in thread
From: Joao Pedro De Almeida Pereira @ 2017-04-27 11:12 UTC (permalink / raw)
To: Murtuza Zabuawala <[email protected]>; +Cc: pgadmin-hackers
Hello Murtuza,
Thanks for the explanation. Based on what you said it looks like a bug in
the library, have you guys considered sending a PR to it?
Thanks
On Thu, Apr 27, 2017, 2:46 AM Murtuza Zabuawala <
[email protected]> wrote:
> +++
> Reference:
> https://www.postgresql.org/message-id/CAKKotZRjqbKAZev81Zk78nikDVXqLKEDV5r%2BsW8Me31Gpzrm_A%40mail.g...
>
> --
> Regards,
> Murtuza Zabuawala
> EnterpriseDB: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
> On Thu, Apr 27, 2017 at 12:09 PM, Murtuza Zabuawala <
> [email protected]> wrote:
>
>> Hello Joao,
>>
>> Yes, We made some changes in SlickGrid library when we integrated it into
>> Query tool.
>>
>> *Issue:* Last row from the query result set was not displaying correctly
>> in query tool when we have scrollbar in grid.
>>
>> The row hight/width pixel size calculations is done inside SlickGrid
>> javascript code, Though we tried solve it through CSS but we had no luck,
>> so we had no other choice but to do it in library it self.
>>
>> The changes were,
>> 1) "getDataLengthIncludingAddNew()" function (slick.grid.js) to add two
>> new rows instead of one when user add values into row (one row is dummy &
>> not visible to user so that it displays last row correctly)
>> 2) Other change was done into "appendRowHtml()" function to calculating
>> the correct number of rows in SlickGrid result as we have added our own
>> custom row as mentioned earlier.
>> 3) Abbreviated long CSS classes as mentioed in README file.
>>
>> Apologies we missed to update this change in README.
>>
>>
>> --
>> Regards,
>> Murtuza Zabuawala
>> EnterpriseDB: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>> On Thu, Apr 27, 2017 at 2:23 AM, Joao Pedro De Almeida Pereira <
>> [email protected]> wrote:
>>
>>> Hello Hackers,
>>>
>>> While doing some changes to the Query Results we found out that there
>>> was a issue with Slick grid.
>>>
>>> The issue that we found was with the CellSelectModel, behaved
>>> differently when pressing Ctrl and Command(Mac). We created a PR
>>> <https://github.com/6pac/SlickGrid/pull/100; with the change to changes
>>> the behavior of the plugin.
>>>
>>> When this PR is applied to the SlickGrid library we need to apply it to
>>> the current version of SlickGrid that we have vendorized.
>>> According to the libraries.txt file we are in version 2.2.4 of the
>>> library but a diff between our code and the libraries version 2.2.4 shows
>>> differences in the code.
>>>
>>> Did we do any change to SlickGrid library that is vendorized? Or is just
>>> the information in libraries.txt that is incorrect?
>>> Does anyone know any problem if we bump the version of SlickGrid to the
>>> newer version after the PR is applied?
>>>
>>> Thanks
>>> Joao
>>>
>>
>>
>
^ permalink raw reply [nested|flat] 9+ messages in thread
* Re: Issue with SlickGrid
2017-04-26 20:53 Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 06:39 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 06:46 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 11:12 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
@ 2017-04-27 12:13 ` Murtuza Zabuawala <[email protected]>
2017-04-27 15:49 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
0 siblings, 1 reply; 9+ messages in thread
From: Murtuza Zabuawala @ 2017-04-27 12:13 UTC (permalink / raw)
To: Joao Pedro De Almeida Pereira <[email protected]>; +Cc: pgadmin-hackers
No, we didn't.
--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Thu, Apr 27, 2017 at 4:42 PM, Joao Pedro De Almeida Pereira <
[email protected]> wrote:
> Hello Murtuza,
> Thanks for the explanation. Based on what you said it looks like a bug in
> the library, have you guys considered sending a PR to it?
>
> Thanks
>
> On Thu, Apr 27, 2017, 2:46 AM Murtuza Zabuawala <murtuza.zabuawala@
> enterprisedb.com> wrote:
>
>> +++
>> Reference: https://www.postgresql.org/message-id/
>> CAKKotZRjqbKAZev81Zk78nikDVXqLKEDV5r%2BsW8Me31Gpzrm_A%40mail.gmail.com
>>
>> --
>> Regards,
>> Murtuza Zabuawala
>> EnterpriseDB: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>> On Thu, Apr 27, 2017 at 12:09 PM, Murtuza Zabuawala <murtuza.zabuawala@
>> enterprisedb.com> wrote:
>>
>>> Hello Joao,
>>>
>>> Yes, We made some changes in SlickGrid library when we integrated it
>>> into Query tool.
>>>
>>> *Issue:* Last row from the query result set was not displaying
>>> correctly in query tool when we have scrollbar in grid.
>>>
>>> The row hight/width pixel size calculations is done inside SlickGrid
>>> javascript code, Though we tried solve it through CSS but we had no luck,
>>> so we had no other choice but to do it in library it self.
>>>
>>> The changes were,
>>> 1) "getDataLengthIncludingAddNew()" function (slick.grid.js) to add two
>>> new rows instead of one when user add values into row (one row is dummy &
>>> not visible to user so that it displays last row correctly)
>>> 2) Other change was done into "appendRowHtml()" function to calculating
>>> the correct number of rows in SlickGrid result as we have added our own
>>> custom row as mentioned earlier.
>>> 3) Abbreviated long CSS classes as mentioed in README file.
>>>
>>> Apologies we missed to update this change in README.
>>>
>>>
>>> --
>>> Regards,
>>> Murtuza Zabuawala
>>> EnterpriseDB: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>> On Thu, Apr 27, 2017 at 2:23 AM, Joao Pedro De Almeida Pereira <
>>> [email protected]> wrote:
>>>
>>>> Hello Hackers,
>>>>
>>>> While doing some changes to the Query Results we found out that there
>>>> was a issue with Slick grid.
>>>>
>>>> The issue that we found was with the CellSelectModel, behaved
>>>> differently when pressing Ctrl and Command(Mac). We created a PR
>>>> <https://github.com/6pac/SlickGrid/pull/100; with the change to
>>>> changes the behavior of the plugin.
>>>>
>>>> When this PR is applied to the SlickGrid library we need to apply it to
>>>> the current version of SlickGrid that we have vendorized.
>>>> According to the libraries.txt file we are in version 2.2.4 of the
>>>> library but a diff between our code and the libraries version 2.2.4 shows
>>>> differences in the code.
>>>>
>>>> Did we do any change to SlickGrid library that is vendorized? Or is
>>>> just the information in libraries.txt that is incorrect?
>>>> Does anyone know any problem if we bump the version of SlickGrid to the
>>>> newer version after the PR is applied?
>>>>
>>>> Thanks
>>>> Joao
>>>>
>>>
>>>
>>
^ permalink raw reply [nested|flat] 9+ messages in thread
* Re: Issue with SlickGrid
2017-04-26 20:53 Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 06:39 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 06:46 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 11:12 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 12:13 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
@ 2017-04-27 15:49 ` Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 15:53 ` Re: Issue with SlickGrid Dave Page <[email protected]>
0 siblings, 1 reply; 9+ messages in thread
From: Joao Pedro De Almeida Pereira @ 2017-04-27 15:49 UTC (permalink / raw)
To: Murtuza Zabuawala <[email protected]>; +Cc: pgadmin-hackers; Matthew Kleiman <[email protected]>
Hi Hackers,
We found that the latest version of SlickGrid fixes the scrollbar issue. We
have upgraded it to the latest version in our vendor directory and updated
the tests accordingly in the attached patch.
We didn't apply any of the custom changes that were previously added.
Please validate that the memory issues that were referenced in the README
file are solved with the latest version of SlickGrid. If we can avoid
changing the code of the libraries that we use, it will be far easier to
continue to upgrade in the future. We will need to upgrade the version of
SlickGrid again soon, once they approve our pull request
<https://github.com/6pac/SlickGrid/pull/100;.
Thanks,
Joao & Matt
On Thu, Apr 27, 2017 at 8:13 AM, Murtuza Zabuawala <
[email protected]> wrote:
> No, we didn't.
>
> --
> Regards,
> Murtuza Zabuawala
> EnterpriseDB: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
> On Thu, Apr 27, 2017 at 4:42 PM, Joao Pedro De Almeida Pereira <
> [email protected]> wrote:
>
>> Hello Murtuza,
>> Thanks for the explanation. Based on what you said it looks like a bug in
>> the library, have you guys considered sending a PR to it?
>>
>> Thanks
>>
>> On Thu, Apr 27, 2017, 2:46 AM Murtuza Zabuawala <
>> [email protected]> wrote:
>>
>>> +++
>>> Reference: https://www.postgresql.org/message-id/CAKKotZRjqb
>>> KAZev81Zk78nikDVXqLKEDV5r%2BsW8Me31Gpzrm_A%40mail.gmail.com
>>>
>>> --
>>> Regards,
>>> Murtuza Zabuawala
>>> EnterpriseDB: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>> On Thu, Apr 27, 2017 at 12:09 PM, Murtuza Zabuawala <
>>> [email protected]> wrote:
>>>
>>>> Hello Joao,
>>>>
>>>> Yes, We made some changes in SlickGrid library when we integrated it
>>>> into Query tool.
>>>>
>>>> *Issue:* Last row from the query result set was not displaying
>>>> correctly in query tool when we have scrollbar in grid.
>>>>
>>>> The row hight/width pixel size calculations is done inside SlickGrid
>>>> javascript code, Though we tried solve it through CSS but we had no luck,
>>>> so we had no other choice but to do it in library it self.
>>>>
>>>> The changes were,
>>>> 1) "getDataLengthIncludingAddNew()" function (slick.grid.js) to add
>>>> two new rows instead of one when user add values into row (one row is dummy
>>>> & not visible to user so that it displays last row correctly)
>>>> 2) Other change was done into "appendRowHtml()" function to calculating
>>>> the correct number of rows in SlickGrid result as we have added our own
>>>> custom row as mentioned earlier.
>>>> 3) Abbreviated long CSS classes as mentioed in README file.
>>>>
>>>> Apologies we missed to update this change in README.
>>>>
>>>>
>>>> --
>>>> Regards,
>>>> Murtuza Zabuawala
>>>> EnterpriseDB: http://www.enterprisedb.com
>>>> The Enterprise PostgreSQL Company
>>>>
>>>> On Thu, Apr 27, 2017 at 2:23 AM, Joao Pedro De Almeida Pereira <
>>>> [email protected]> wrote:
>>>>
>>>>> Hello Hackers,
>>>>>
>>>>> While doing some changes to the Query Results we found out that there
>>>>> was a issue with Slick grid.
>>>>>
>>>>> The issue that we found was with the CellSelectModel, behaved
>>>>> differently when pressing Ctrl and Command(Mac). We created a PR
>>>>> <https://github.com/6pac/SlickGrid/pull/100; with the change to
>>>>> changes the behavior of the plugin.
>>>>>
>>>>> When this PR is applied to the SlickGrid library we need to apply it
>>>>> to the current version of SlickGrid that we have vendorized.
>>>>> According to the libraries.txt file we are in version 2.2.4 of the
>>>>> library but a diff between our code and the libraries version 2.2.4 shows
>>>>> differences in the code.
>>>>>
>>>>> Did we do any change to SlickGrid library that is vendorized? Or is
>>>>> just the information in libraries.txt that is incorrect?
>>>>> Does anyone know any problem if we bump the version of SlickGrid to
>>>>> the newer version after the PR is applied?
>>>>>
>>>>> Thanks
>>>>> Joao
>>>>>
>>>>
>>>>
>>>
>
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers
Attachments:
[application/octet-stream] 0001-Update-SlickGrid-to-latest-version.patch (317.2K, 3-0001-Update-SlickGrid-to-latest-version.patch)
download | inline diff:
From 000fcf03b25fa465f4a03620f915e07469585009 Mon Sep 17 00:00:00 2001
From: Joao Pereira and Matt Kleiman <[email protected]>
Date: Thu, 27 Apr 2017 11:40:43 -0400
Subject: [PATCH] Update SlickGrid to latest version
version 2.3.4 on commit 1878074
- This latest version fixes the scrollbar issue, so no need for custom changes to SlickGrid code.
- Reverted css changes: using original .slick-row and .slick-cell classes
---
libraries.txt | 66 +-
.../copy_selected_query_results_feature_test.py | 2 +-
web/pgadmin/static/vendor/slickgrid/README | 9 -
web/pgadmin/static/vendor/slickgrid/README.md | 9 +
.../slickgrid/controls/slick.columnpicker.js | 9 +-
.../static/vendor/slickgrid/images/CheckboxN.png | Bin 0 -> 257 bytes
.../static/vendor/slickgrid/images/CheckboxY.png | Bin 0 -> 361 bytes
.../vendor/slickgrid/plugins/slick.autotooltips.js | 10 +-
.../slickgrid/plugins/slick.cellcopymanager.js | 6 +-
.../plugins/slick.cellexternalcopymanager.js | 449 ++
.../slickgrid/plugins/slick.cellselectionmodel.js | 44 +-
.../slickgrid/plugins/slick.headerbuttons.js | 6 +-
.../vendor/slickgrid/plugins/slick.headermenu.js | 8 +-
.../slickgrid/plugins/slick.rowselectionmodel.js | 8 +-
.../vendor/slickgrid/slick-default-theme.css | 22 +-
web/pgadmin/static/vendor/slickgrid/slick.core.js | 15 +-
.../static/vendor/slickgrid/slick.dataview.js | 40 +-
.../static/vendor/slickgrid/slick.editors.js | 67 +-
.../static/vendor/slickgrid/slick.formatters.js | 12 +-
web/pgadmin/static/vendor/slickgrid/slick.grid.css | 43 +-
web/pgadmin/static/vendor/slickgrid/slick.grid.js | 7375 ++++++++++----------
.../slickgrid/slick.groupitemmetadataprovider.js | 158 +
.../vendor/slickgrid/slick.remotemodel-yahoo.js | 206 +
.../static/vendor/slickgrid/slick.remotemodel.js | 169 +
.../tools/sqleditor/static/css/sqleditor.css | 16 +-
.../javascript/selection/row_selector_spec.js | 34 +-
26 files changed, 4989 insertions(+), 3794 deletions(-)
delete mode 100644 web/pgadmin/static/vendor/slickgrid/README
create mode 100644 web/pgadmin/static/vendor/slickgrid/README.md
create mode 100644 web/pgadmin/static/vendor/slickgrid/images/CheckboxN.png
create mode 100644 web/pgadmin/static/vendor/slickgrid/images/CheckboxY.png
create mode 100644 web/pgadmin/static/vendor/slickgrid/plugins/slick.cellexternalcopymanager.js
create mode 100644 web/pgadmin/static/vendor/slickgrid/slick.groupitemmetadataprovider.js
create mode 100644 web/pgadmin/static/vendor/slickgrid/slick.remotemodel-yahoo.js
create mode 100644 web/pgadmin/static/vendor/slickgrid/slick.remotemodel.js
diff --git a/libraries.txt b/libraries.txt
index 7e0bd5b7..4076ab59 100644
--- a/libraries.txt
+++ b/libraries.txt
@@ -1,36 +1,36 @@
This is a list of the third party libraries/code used in the application, not
including Python modules installed via Pip which are listed in requirements.txt.
-Library Version Licence URL
-======= ======= ======= ===
-QT 4.6.2+ LGPL v2.1/3 http://www.qt.io/
-Bootstrap 3.3.4 MIT http://getbootstrap.com/
-jQuery 1.11.1 MIT http://jquery.com/
-Modernizr 2.6.2 MIT/BSD http://modernizr.com/
-AlertifyJS 1.7.1 MIT http://alertifyjs.com/ *** Do not update - changed to GPL3 in 1.8.0 ***
-CodeMirror 5.14.2 MIT http://codemirror.net/
-aciTree 4.5.0-rc.7 MIT/GPL http://acoderinsights.ro/en/aciTree-tree-view-with-jQuery
-contextMenu 2.1.0 MIT https://github.com/swisnl/jQuery-contextMenu
-wcDocker 0f5690318c MIT/GPL https://github.com/WebCabin/wcDocker
-Require.js 2.1.18 BSD/MIT http://requirejs.org/
-Underscore.js 1.8.3 MIT http://underscorejs.org/
-Underscore.string 387ab72d49 MIT http://epeli.github.io/underscore.string/
-Backform.js 5859b4f9db MIT https://github.com/AmiliaApp/backform
-Backbone 1.1.2 MIT http://backbonejs.org
-font-Awesome 4.5 SIL OFL http://fortawesome.github.io/Font-Awesome/
-font-mfizz 2.3 MIT http://fizzed.com/oss/font-mfizz
-backgrid.js 0.3.5 MIT http://backgridjs.com/
-backbone.undo 0.2 MIT http://backbone.undojs.com/
-bootstrap-switch 3.3.2 MIT http://www.bootstrap-switch.org/
-select2 4.0.1 MIT https://select2.github.io/
-backgrid-filter 01b2b21 MIT https://github.com/wyuenho/backgrid-filter
-backbone.paginator 2.0.3 MIT http://github.com/backbone-paginator/backbone.paginator
-backgrid-paginator 03632df MIT https://github.com/wyuenho/backgrid-paginator
-backgrid-select-all 1a00053 MIT https://github.com/wyuenho/backgrid-select-all
-dropzone 4e20bd4 MIT https://github.com/enyo/dropzone
-Filemanager 7e060c2 MIT https://github.com/simogeo/Filemanager
-Unit (Length) d8e6237 MIT https://github.com/heygrady/Units/blob/master/Length.min.js
-Natural Sort 9565816 MIT https://github.com/javve/natural-sort/blob/master/index.js
-SlickGrid 2.2.4 MIT https://github.com/6pac/SlickGrid
-jQuery-UI 1.11.3 MIT https://jqueryui.com/
-BigNumber 3.0.1 MIT http://mikemcl.github.io/bignumber.js
\ No newline at end of file
+Library Version Licence URL
+======= ======= ======= ===
+QT 4.6.2+ LGPL v2.1/3 http://www.qt.io/
+Bootstrap 3.3.4 MIT http://getbootstrap.com/
+jQuery 1.11.1 MIT http://jquery.com/
+Modernizr 2.6.2 MIT/BSD http://modernizr.com/
+AlertifyJS 1.7.1 MIT http://alertifyjs.com/ *** Do not update - changed to GPL3 in 1.8.0 ***
+CodeMirror 5.14.2 MIT http://codemirror.net/
+aciTree 4.5.0-rc.7 MIT/GPL http://acoderinsights.ro/en/aciTree-tree-view-with-jQuery
+contextMenu 2.1.0 MIT https://github.com/swisnl/jQuery-contextMenu
+wcDocker 0f5690318c MIT/GPL https://github.com/WebCabin/wcDocker
+Require.js 2.1.18 BSD/MIT http://requirejs.org/
+Underscore.js 1.8.3 MIT http://underscorejs.org/
+Underscore.string 387ab72d49 MIT http://epeli.github.io/underscore.string/
+Backform.js 5859b4f9db MIT https://github.com/AmiliaApp/backform
+Backbone 1.1.2 MIT http://backbonejs.org
+font-Awesome 4.5 SIL OFL http://fortawesome.github.io/Font-Awesome/
+font-mfizz 2.3 MIT http://fizzed.com/oss/font-mfizz
+backgrid.js 0.3.5 MIT http://backgridjs.com/
+backbone.undo 0.2 MIT http://backbone.undojs.com/
+bootstrap-switch 3.3.2 MIT http://www.bootstrap-switch.org/
+select2 4.0.1 MIT https://select2.github.io/
+backgrid-filter 01b2b21 MIT https://github.com/wyuenho/backgrid-filter
+backbone.paginator 2.0.3 MIT http://github.com/backbone-paginator/backbone.paginator
+backgrid-paginator 03632df MIT https://github.com/wyuenho/backgrid-paginator
+backgrid-select-all 1a00053 MIT https://github.com/wyuenho/backgrid-select-all
+dropzone 4e20bd4 MIT https://github.com/enyo/dropzone
+Filemanager 7e060c2 MIT https://github.com/simogeo/Filemanager
+Unit (Length) d8e6237 MIT https://github.com/heygrady/Units/blob/master/Length.min.js
+Natural Sort 9565816 MIT https://github.com/javve/natural-sort/blob/master/index.js
+SlickGrid 2.3.4-1878074 MIT https://github.com/6pac/SlickGrid
+jQuery-UI 1.11.3 MIT https://jqueryui.com/
+BigNumber 3.0.1 MIT http://mikemcl.github.io/bignumber.js
\ No newline at end of file
diff --git a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
index 223579ee..d0e6394d 100644
--- a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
+++ b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py
@@ -47,7 +47,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
def _copies_rows(self):
pyperclip.copy("old clipboard contents")
time.sleep(5)
- self.page.find_by_xpath("//*[contains(@class, 'sr')]/*[1]/input[@type='checkbox']").click()
+ self.page.find_by_xpath("//*[contains(@class, 'slick-row')]/*[1]/input[@type='checkbox']").click()
self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
self.assertEqual("'Some-Name','6'",
diff --git a/web/pgadmin/static/vendor/slickgrid/README b/web/pgadmin/static/vendor/slickgrid/README
deleted file mode 100644
index cf583515..00000000
--- a/web/pgadmin/static/vendor/slickgrid/README
+++ /dev/null
@@ -1,9 +0,0 @@
-WARNING!!
-
-The following changes have been made to SlickGrid. These must be re-applied if updating the code from upstream!
-
-- The CSS class 'slick-row' has been renamed to 'sr'
-
-- The CSS class 'slick-cell' has been renamed to 'sc'
-
-The intent of these changes is to minimise memory usage by the grid, by saving a few bytes per row/cell.
\ No newline at end of file
diff --git a/web/pgadmin/static/vendor/slickgrid/README.md b/web/pgadmin/static/vendor/slickgrid/README.md
new file mode 100644
index 00000000..e8a1ad7a
--- /dev/null
+++ b/web/pgadmin/static/vendor/slickgrid/README.md
@@ -0,0 +1,9 @@
+## This is the 6pac SlickGrid repo
+
+This is the acknowledged most active non-customised fork of SlickGrid.
+
+It aims to be a viable alternative master repo, building on the legacy of the mleibman/SlickGrid master branch, keeping libraries up to date and applying small, safe core patches and enhancements without turning into a personalised build.
+
+Check out the [examples](https://github.com/6pac/SlickGrid/wiki/Examples) for examples demonstrating new features and use cases, such as dynamic grid creation and editors with third party controls.
+
+Also check out the [wiki](https://github.com/6pac/SlickGrid/wiki) for news and documentation.
\ No newline at end of file
diff --git a/web/pgadmin/static/vendor/slickgrid/controls/slick.columnpicker.js b/web/pgadmin/static/vendor/slickgrid/controls/slick.columnpicker.js
index dc167209..93a6be5b 100644
--- a/web/pgadmin/static/vendor/slickgrid/controls/slick.columnpicker.js
+++ b/web/pgadmin/static/vendor/slickgrid/controls/slick.columnpicker.js
@@ -12,12 +12,12 @@
grid.onColumnsReordered.subscribe(updateColumnOrder);
options = $.extend({}, defaults, options);
- $menu = $("<span class='slick-columnpicker' style='display:none;position:absolute;z-index:20;' />").appendTo(document.body);
+ $menu = $("<span class='slick-columnpicker' style='display:none;position:absolute;z-index:20;overflow-y:scroll;' />").appendTo(document.body);
- $menu.bind("mouseleave", function (e) {
+ $menu.on("mouseleave", function (e) {
$(this).fadeOut(options.fadeSpeed)
});
- $menu.bind("click", updateColumn);
+ $menu.on("click", updateColumn);
}
@@ -44,7 +44,7 @@
}
$("<label />")
- .text(columns[i].name)
+ .html(columns[i].name)
.prepend($input)
.appendTo($li);
}
@@ -73,6 +73,7 @@
$menu
.css("top", e.pageY - 10)
.css("left", e.pageX - 10)
+ .css("max-height", $(window).height() - e.pageY -10)
.fadeIn(options.fadeSpeed);
}
diff --git a/web/pgadmin/static/vendor/slickgrid/images/CheckboxN.png b/web/pgadmin/static/vendor/slickgrid/images/CheckboxN.png
new file mode 100644
index 0000000000000000000000000000000000000000..072ecbb96435c4822374cb3116fca5819194363e
GIT binary patch
literal 257
zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3Ea{HEjtmSN`?>!lvI6;>1s;*b
zKsARzm{C;2s{tq|S>hT|5}cn_Ql40p%21G)nOCBhms+A=qGzCIXynY2{RXJ0&eO#)
zL?ig>B}2Xz1rgW4@B8_c0=zQP7!PQ@;Yl%a_HX5{m2JFHW&PiNA;a`vJKVfA?^S2N
zz1F(0n6E)ZujPY$i>}E^!)NBa4I$aJKFkWDPH!$V#Cc2&n!`IOXj0uei+8)WFEMnh
wdGKZ{w|Q5nSEq>ooZ^3chi-4HUvN!$+qFOEue>{c3+NICPgg&ebxsLQ07+L^=>Px#
literal 0
HcmV?d00001
diff --git a/web/pgadmin/static/vendor/slickgrid/images/CheckboxY.png b/web/pgadmin/static/vendor/slickgrid/images/CheckboxY.png
new file mode 100644
index 0000000000000000000000000000000000000000..467f3010896f438d0ede54760ba1aec7da3161ed
GIT binary patch
literal 361
zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3Ea{HEjtmSN`?>!lvI6;>1s;*b
zKsARzm{C;2s{tq|S>hT|5}cn_Ql40p%21G)nOCBhms+A=qGzCIXynY2{RXJ$nWu|m
zh(>VlC4KH@2Z`e!_ijrR$!YSOoUkox>o2Votq8Sgs*|O7*k*4qo3iny@4M%B4{y7j
zyCGlT{m%ZT`m)#eb4wzp?ONBp$igczB2<(iaL2ODclL+$OfK4-&kxGIeQR5<@;Szi
zWtmli(rpI~cw7Tbd|&V4Yse6BO*cGV_-%~=&qfx3jQijBy?-ph!dSlU^(JmtuEa>O
zZKbi#&zbo0><?IDd;T%U%2iR*RLfsXUbOt&rXK$a{aGrUXJ<U?{}d;4+{Ir<%KKyN
zqQ@3Vjn(o?KDcc(^%V}Rc~m)Xz5Su>cmFk()-t50omKnUdI%IO44$rjF6*2UngHN5
BjpYCU
literal 0
HcmV?d00001
diff --git a/web/pgadmin/static/vendor/slickgrid/plugins/slick.autotooltips.js b/web/pgadmin/static/vendor/slickgrid/plugins/slick.autotooltips.js
index 6633bb70..ffa93e0d 100644
--- a/web/pgadmin/static/vendor/slickgrid/plugins/slick.autotooltips.js
+++ b/web/pgadmin/static/vendor/slickgrid/plugins/slick.autotooltips.js
@@ -21,7 +21,7 @@
enableForHeaderCells: false,
maxToolTipLength: null
};
-
+
/**
* Initialize plugin.
*/
@@ -31,7 +31,7 @@
if (options.enableForCells) _grid.onMouseEnter.subscribe(handleMouseEnter);
if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.subscribe(handleHeaderMouseEnter);
}
-
+
/**
* Destroy plugin.
*/
@@ -39,7 +39,7 @@
if (options.enableForCells) _grid.onMouseEnter.unsubscribe(handleMouseEnter);
if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.unsubscribe(handleHeaderMouseEnter);
}
-
+
/**
* Handle mouse entering grid cell to add/remove tooltip.
* @param {jQuery.Event} e - The event
@@ -60,7 +60,7 @@
$node.attr("title", text);
}
}
-
+
/**
* Handle mouse entering header cell to add/remove tooltip.
* @param {jQuery.Event} e - The event
@@ -73,7 +73,7 @@
$node.attr("title", ($node.innerWidth() < $node[0].scrollWidth) ? column.name : "");
}
}
-
+
// Public API
$.extend(this, {
"init": init,
diff --git a/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellcopymanager.js b/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellcopymanager.js
index c74018de..66c2376c 100644
--- a/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellcopymanager.js
+++ b/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellcopymanager.js
@@ -46,10 +46,12 @@
if (e.which == 86 && (e.ctrlKey || e.metaKey)) {
if (_copiedRanges) {
e.preventDefault();
- clearCopySelection();
ranges = _grid.getSelectionModel().getSelectedRanges();
_self.onPasteCells.notify({from: _copiedRanges, to: ranges});
- _copiedRanges = null;
+ if (!_grid.getOptions().preserveCopiedSelectionOnPaste) {
+ clearCopySelection();
+ _copiedRanges = null;
+ }
}
}
}
diff --git a/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellexternalcopymanager.js b/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellexternalcopymanager.js
new file mode 100644
index 00000000..fec7cb2a
--- /dev/null
+++ b/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellexternalcopymanager.js
@@ -0,0 +1,449 @@
+(function ($) {
+ // register namespace
+ $.extend(true, window, {
+ "Slick": {
+ "CellExternalCopyManager": CellExternalCopyManager
+ }
+ });
+
+
+ function CellExternalCopyManager(options) {
+ /*
+ This manager enables users to copy/paste data from/to an external Spreadsheet application
+ such as MS-Excel® or OpenOffice-Spreadsheet.
+
+ Since it is not possible to access directly the clipboard in javascript, the plugin uses
+ a trick to do it's job. After detecting the keystroke, we dynamically create a textarea
+ where the browser copies/pastes the serialized data.
+
+ options:
+ copiedCellStyle : sets the css className used for copied cells. default : "copied"
+ copiedCellStyleLayerKey : sets the layer key for setting css values of copied cells. default : "copy-manager"
+ dataItemColumnValueExtractor : option to specify a custom column value extractor function
+ dataItemColumnValueSetter : option to specify a custom column value setter function
+ clipboardCommandHandler : option to specify a custom handler for paste actions
+ includeHeaderWhenCopying : set to true and the plugin will take the name property from each column (which is usually what appears in your header) and put that as the first row of the text that's copied to the clipboard
+ bodyElement: option to specify a custom DOM element which to will be added the hidden textbox. It's useful if the grid is inside a modal dialog.
+ onCopyInit: optional handler to run when copy action initializes
+ onCopySuccess: optional handler to run when copy action is complete
+ newRowCreator: function to add rows to table if paste overflows bottom of table
+ readOnlyMode: suppresses paste
+ */
+ var _grid;
+ var _self = this;
+ var _copiedRanges;
+ var _options = options || {};
+ var _copiedCellStyleLayerKey = _options.copiedCellStyleLayerKey || "copy-manager";
+ var _copiedCellStyle = _options.copiedCellStyle || "copied";
+ var _clearCopyTI = 0;
+ var _bodyElement = _options.bodyElement || document.body;
+ var _onCopyInit = _options.onCopyInit || null;
+ var _onCopySuccess = _options.onCopySuccess || null;
+
+ var keyCodes = {
+ 'C': 67,
+ 'V': 86,
+ 'ESC': 27,
+ 'INSERT': 45
+ };
+
+ function init(grid) {
+ _grid = grid;
+ _grid.onKeyDown.subscribe(handleKeyDown);
+
+ // we need a cell selection model
+ var cellSelectionModel = grid.getSelectionModel();
+ if (!cellSelectionModel){
+ throw new Error("Selection model is mandatory for this plugin. Please set a selection model on the grid before adding this plugin: grid.setSelectionModel(new Slick.CellSelectionModel())");
+ }
+ // we give focus on the grid when a selection is done on it.
+ // without this, if the user selects a range of cell without giving focus on a particular cell, the grid doesn't get the focus and key stroke handles (ctrl+c) don't work
+ cellSelectionModel.onSelectedRangesChanged.subscribe(function(e, args){
+ _grid.focus();
+ });
+ }
+
+ function destroy() {
+ _grid.onKeyDown.unsubscribe(handleKeyDown);
+ }
+
+ function getDataItemValueForColumn(item, columnDef) {
+ if (_options.dataItemColumnValueExtractor) {
+ var dataItemColumnValueExtractorValue = _options.dataItemColumnValueExtractor(item, columnDef);
+
+ if (dataItemColumnValueExtractorValue)
+ return dataItemColumnValueExtractorValue;
+ }
+
+ var retVal = '';
+
+ // if a custom getter is not defined, we call serializeValue of the editor to serialize
+ if (columnDef.editor){
+ var editorArgs = {
+ 'container':$("<p>"), // a dummy container
+ 'column':columnDef,
+ 'position':{'top':0, 'left':0}, // a dummy position required by some editors
+ 'grid':_grid
+ };
+ var editor = new columnDef.editor(editorArgs);
+ editor.loadValue(item);
+ retVal = editor.serializeValue();
+ editor.destroy();
+ }
+ else {
+ retVal = item[columnDef.field];
+ }
+
+ return retVal;
+ }
+
+ function setDataItemValueForColumn(item, columnDef, value) {
+ if (_options.dataItemColumnValueSetter) {
+ return _options.dataItemColumnValueSetter(item, columnDef, value);
+ }
+
+ // if a custom setter is not defined, we call applyValue of the editor to unserialize
+ if (columnDef.editor){
+ var editorArgs = {
+ 'container':$("body"), // a dummy container
+ 'column':columnDef,
+ 'position':{'top':0, 'left':0}, // a dummy position required by some editors
+ 'grid':_grid
+ };
+ var editor = new columnDef.editor(editorArgs);
+ editor.loadValue(item);
+ editor.applyValue(item, value);
+ editor.destroy();
+ }
+ }
+
+
+ function _createTextBox(innerText){
+ var ta = document.createElement('textarea');
+ ta.style.position = 'absolute';
+ ta.style.left = '-1000px';
+ ta.style.top = document.body.scrollTop + 'px';
+ ta.value = innerText;
+ _bodyElement.appendChild(ta);
+ ta.select();
+
+ return ta;
+ }
+
+ function _decodeTabularData(_grid, ta){
+ var columns = _grid.getColumns();
+ var clipText = ta.value;
+ var clipRows = clipText.split(/[\n\f\r]/);
+ // trim trailing CR if present
+ if (clipRows[clipRows.length - 1]=="") { clipRows.pop(); }
+
+ var clippedRange = [];
+ var j = 0;
+
+ _bodyElement.removeChild(ta);
+ for (var i=0; i<clipRows.length; i++) {
+ if (clipRows[i]!="")
+ clippedRange[j++] = clipRows[i].split("\t");
+ else
+ clippedRange[i] = [""];
+ }
+ var selectedCell = _grid.getActiveCell();
+ var ranges = _grid.getSelectionModel().getSelectedRanges();
+ var selectedRange = ranges && ranges.length ? ranges[0] : null; // pick only one selection
+ var activeRow = null;
+ var activeCell = null;
+
+ if (selectedRange){
+ activeRow = selectedRange.fromRow;
+ activeCell = selectedRange.fromCell;
+ } else if (selectedCell){
+ activeRow = selectedCell.row;
+ activeCell = selectedCell.cell;
+ } else {
+ // we don't know where to paste
+ return;
+ }
+
+ var oneCellToMultiple = false;
+ var destH = clippedRange.length;
+ var destW = clippedRange.length ? clippedRange[0].length : 0;
+ if (clippedRange.length == 1 && clippedRange[0].length == 1 && selectedRange){
+ oneCellToMultiple = true;
+ destH = selectedRange.toRow - selectedRange.fromRow +1;
+ destW = selectedRange.toCell - selectedRange.fromCell +1;
+ }
+ var availableRows = _grid.getData().length - activeRow;
+ var addRows = 0;
+ if(availableRows < destH)
+ {
+ var d = _grid.getData();
+ for(addRows = 1; addRows <= destH - availableRows; addRows++)
+ d.push({});
+ _grid.setData(d);
+ _grid.render();
+ }
+
+ var overflowsBottomOfGrid = activeRow + destH > _grid.getDataLength();
+
+ if (_options.newRowCreator && overflowsBottomOfGrid) {
+
+ var newRowsNeeded = activeRow + destH - _grid.getDataLength();
+
+ _options.newRowCreator(newRowsNeeded);
+
+ }
+
+ var clipCommand = {
+
+ isClipboardCommand: true,
+ clippedRange: clippedRange,
+ oldValues: [],
+ cellExternalCopyManager: _self,
+ _options: _options,
+ setDataItemValueForColumn: setDataItemValueForColumn,
+ markCopySelection: markCopySelection,
+ oneCellToMultiple: oneCellToMultiple,
+ activeRow: activeRow,
+ activeCell: activeCell,
+ destH: destH,
+ destW: destW,
+ maxDestY: _grid.getDataLength(),
+ maxDestX: _grid.getColumns().length,
+ h: 0,
+ w: 0,
+
+ execute: function() {
+ this.h=0;
+ for (var y = 0; y < this.destH; y++){
+ this.oldValues[y] = [];
+ this.w=0;
+ this.h++;
+ for (var x = 0; x < this.destW; x++){
+ this.w++;
+ var desty = activeRow + y;
+ var destx = activeCell + x;
+
+ if (desty < this.maxDestY && destx < this.maxDestX ) {
+ var nd = _grid.getCellNode(desty, destx);
+ var dt = _grid.getDataItem(desty);
+ this.oldValues[y][x] = dt[columns[destx]['field']];
+ if (oneCellToMultiple)
+ this.setDataItemValueForColumn(dt, columns[destx], clippedRange[0][0]);
+ else
+ this.setDataItemValueForColumn(dt, columns[destx], clippedRange[y] ? clippedRange[y][x] : '');
+ _grid.updateCell(desty, destx);
+ _grid.onCellChange.notify({
+ row: desty,
+ cell: destx,
+ item: dt,
+ grid: _grid
+ });
+
+ }
+ }
+ }
+
+ var bRange = {
+ 'fromCell': activeCell,
+ 'fromRow': activeRow,
+ 'toCell': activeCell+this.w-1,
+ 'toRow': activeRow+this.h-1
+ }
+
+ this.markCopySelection([bRange]);
+ _grid.getSelectionModel().setSelectedRanges([bRange]);
+ this.cellExternalCopyManager.onPasteCells.notify({ranges: [bRange]});
+ },
+
+ undo: function() {
+ for (var y = 0; y < this.destH; y++){
+ for (var x = 0; x < this.destW; x++){
+ var desty = activeRow + y;
+ var destx = activeCell + x;
+
+ if (desty < this.maxDestY && destx < this.maxDestX ) {
+ var nd = _grid.getCellNode(desty, destx);
+ var dt = _grid.getDataItem(desty);
+ if (oneCellToMultiple)
+ this.setDataItemValueForColumn(dt, columns[destx], this.oldValues[0][0]);
+ else
+ this.setDataItemValueForColumn(dt, columns[destx], this.oldValues[y][x]);
+ _grid.updateCell(desty, destx);
+ _grid.onCellChange.notify({
+ row: desty,
+ cell: destx,
+ item: dt,
+ grid: _grid
+ });
+ }
+ }
+ }
+
+ var bRange = {
+ 'fromCell': activeCell,
+ 'fromRow': activeRow,
+ 'toCell': activeCell+this.w-1,
+ 'toRow': activeRow+this.h-1
+ }
+
+ this.markCopySelection([bRange]);
+ _grid.getSelectionModel().setSelectedRanges([bRange]);
+ this.cellExternalCopyManager.onPasteCells.notify({ranges: [bRange]});
+
+ if(addRows > 1){
+ var d = _grid.getData();
+ for(; addRows > 1; addRows--)
+ d.splice(d.length - 1, 1);
+ _grid.setData(d);
+ _grid.render();
+ }
+ }
+ };
+
+ if(_options.clipboardCommandHandler) {
+ _options.clipboardCommandHandler(clipCommand);
+ }
+ else {
+ clipCommand.execute();
+ }
+ }
+
+
+ function handleKeyDown(e, args) {
+ var ranges;
+ if (!_grid.getEditorLock().isActive() || _grid.getOptions().autoEdit) {
+ if (e.which == keyCodes.ESC) {
+ if (_copiedRanges) {
+ e.preventDefault();
+ clearCopySelection();
+ _self.onCopyCancelled.notify({ranges: _copiedRanges});
+ _copiedRanges = null;
+ }
+ }
+
+ if ((e.which === keyCodes.C || e.which === keyCodes.INSERT) && (e.ctrlKey || e.metaKey) && !e.shiftKey) { // CTRL+C or CTRL+INS
+ if (_onCopyInit) {
+ _onCopyInit.call();
+ }
+ ranges = _grid.getSelectionModel().getSelectedRanges();
+ if (ranges.length != 0) {
+ _copiedRanges = ranges;
+ markCopySelection(ranges);
+ _self.onCopyCells.notify({ranges: ranges});
+
+ var columns = _grid.getColumns();
+ var clipText = "";
+
+ for (var rg = 0; rg < ranges.length; rg++){
+ var range = ranges[rg];
+ var clipTextRows = [];
+ for (var i=range.fromRow; i< range.toRow+1 ; i++){
+ var clipTextCells = [];
+ var dt = _grid.getDataItem(i);
+
+ if (clipTextRows == "" && _options.includeHeaderWhenCopying) {
+ var clipTextHeaders = [];
+ for (var j = range.fromCell; j < range.toCell + 1 ; j++) {
+ if (columns[j].name.length > 0)
+ clipTextHeaders.push(columns[j].name);
+ }
+ clipTextRows.push(clipTextHeaders.join("\t"));
+ }
+
+ for (var j=range.fromCell; j< range.toCell+1 ; j++){
+ clipTextCells.push(getDataItemValueForColumn(dt, columns[j]));
+ }
+ clipTextRows.push(clipTextCells.join("\t"));
+ }
+ clipText += clipTextRows.join("\r\n") + "\r\n";
+ }
+
+ if(window.clipboardData) {
+ window.clipboardData.setData("Text", clipText);
+ return true;
+ }
+ else {
+ var focusEl = document.activeElement;
+
+ var ta = _createTextBox(clipText);
+
+ ta.focus();
+
+ setTimeout(function(){
+ _bodyElement.removeChild(ta);
+ // restore focus
+ if (focusEl)
+ focusEl.focus();
+ else
+ console.log("Not element to restore focus to after copy?");
+
+ }, 100);
+
+ if (_onCopySuccess) {
+ var rowCount = 0;
+ // If it's cell selection, use the toRow/fromRow fields
+ if (ranges.length === 1) {
+ rowCount = (ranges[0].toRow + 1) - ranges[0].fromRow;
+ }
+ else {
+ rowCount = ranges.length;
+ }
+ _onCopySuccess.call(this, rowCount);
+ }
+
+ return false;
+ }
+ }
+ }
+
+ if (!_options.readOnlyMode && (
+ (e.which === keyCodes.V && (e.ctrlKey || e.metaKey) && !e.shiftKey)
+ || (e.which === keyCodes.INSERT && e.shiftKey && !e.ctrlKey)
+ )) { // CTRL+V or Shift+INS
+ var ta = _createTextBox('');
+
+ setTimeout(function(){
+ _decodeTabularData(_grid, ta);
+ }, 100);
+
+ return false;
+ }
+ }
+ }
+
+ function markCopySelection(ranges) {
+ clearCopySelection();
+
+ var columns = _grid.getColumns();
+ var hash = {};
+ for (var i = 0; i < ranges.length; i++) {
+ for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
+ hash[j] = {};
+ for (var k = ranges[i].fromCell; k <= ranges[i].toCell && k<columns.length; k++) {
+ hash[j][columns[k].id] = _copiedCellStyle;
+ }
+ }
+ }
+ _grid.setCellCssStyles(_copiedCellStyleLayerKey, hash);
+ clearTimeout(_clearCopyTI);
+ _clearCopyTI = setTimeout(function(){
+ _self.clearCopySelection();
+ }, 2000);
+ }
+
+ function clearCopySelection() {
+ _grid.removeCellCssStyles(_copiedCellStyleLayerKey);
+ }
+
+ $.extend(this, {
+ "init": init,
+ "destroy": destroy,
+ "clearCopySelection": clearCopySelection,
+ "handleKeyDown":handleKeyDown,
+
+ "onCopyCells": new Slick.Event(),
+ "onCopyCancelled": new Slick.Event(),
+ "onPasteCells": new Slick.Event()
+ });
+ }
+})(jQuery);
diff --git a/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellselectionmodel.js b/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellselectionmodel.js
index 07453ed1..3d9e2af0 100644
--- a/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellselectionmodel.js
+++ b/web/pgadmin/static/vendor/slickgrid/plugins/slick.cellselectionmodel.js
@@ -83,49 +83,49 @@
setSelectedRanges([new Slick.Range(args.row, args.cell)]);
}
}
-
+
function handleKeyDown(e) {
/***
* Кey codes
* 37 left
* 38 up
* 39 right
- * 40 down
- */
+ * 40 down
+ */
var ranges, last;
- var active = _grid.getActiveCell();
+ var active = _grid.getActiveCell();
- if ( active && e.shiftKey && !e.ctrlKey && !e.altKey &&
+ if ( active && e.shiftKey && !e.ctrlKey && !e.altKey &&
(e.which == 37 || e.which == 39 || e.which == 38 || e.which == 40) ) {
-
+
ranges = getSelectedRanges();
if (!ranges.length)
ranges.push(new Slick.Range(active.row, active.cell));
-
- // keyboard can work with last range only
+
+ // keyboard can work with last range only
last = ranges.pop();
-
+
// can't handle selection out of active cell
if (!last.contains(active.row, active.cell))
last = new Slick.Range(active.row, active.cell);
-
+
var dRow = last.toRow - last.fromRow,
dCell = last.toCell - last.fromCell,
// walking direction
dirRow = active.row == last.fromRow ? 1 : -1,
dirCell = active.cell == last.fromCell ? 1 : -1;
-
+
if (e.which == 37) {
- dCell -= dirCell;
+ dCell -= dirCell;
} else if (e.which == 39) {
- dCell += dirCell ;
+ dCell += dirCell ;
} else if (e.which == 38) {
- dRow -= dirRow;
+ dRow -= dirRow;
} else if (e.which == 40) {
- dRow += dirRow;
+ dRow += dirRow;
}
-
- // define new selection range
+
+ // define new selection range
var new_last = new Slick.Range(active.row, active.cell, active.row + dirRow*dRow, active.cell + dirCell*dCell);
if (removeInvalidRanges([new_last]).length) {
ranges.push(new_last);
@@ -134,14 +134,14 @@
_grid.scrollRowIntoView(viewRow);
_grid.scrollCellIntoView(viewRow, viewCell);
}
- else
+ else
ranges.push(last);
- setSelectedRanges(ranges);
-
+ setSelectedRanges(ranges);
+
e.preventDefault();
- e.stopPropagation();
- }
+ e.stopPropagation();
+ }
}
$.extend(this, {
diff --git a/web/pgadmin/static/vendor/slickgrid/plugins/slick.headerbuttons.js b/web/pgadmin/static/vendor/slickgrid/plugins/slick.headerbuttons.js
index 8e612735..d7c06195 100644
--- a/web/pgadmin/static/vendor/slickgrid/plugins/slick.headerbuttons.js
+++ b/web/pgadmin/static/vendor/slickgrid/plugins/slick.headerbuttons.js
@@ -122,11 +122,11 @@
}
if (button.handler) {
- btn.bind("click", button.handler);
+ btn.on("click", button.handler);
}
btn
- .bind("click", handleButtonClick)
+ .on("click", handleButtonClick)
.appendTo(args.node);
}
}
@@ -174,4 +174,4 @@
"onCommand": new Slick.Event()
});
}
-})(jQuery);
\ No newline at end of file
+})(jQuery);
diff --git a/web/pgadmin/static/vendor/slickgrid/plugins/slick.headermenu.js b/web/pgadmin/static/vendor/slickgrid/plugins/slick.headermenu.js
index ec8244da..c4032301 100644
--- a/web/pgadmin/static/vendor/slickgrid/plugins/slick.headermenu.js
+++ b/web/pgadmin/static/vendor/slickgrid/plugins/slick.headermenu.js
@@ -100,13 +100,13 @@
_grid.setColumns(_grid.getColumns());
// Hide the menu on outside click.
- $(document.body).bind("mousedown", handleBodyMouseDown);
+ $(document.body).on("mousedown", handleBodyMouseDown);
}
function destroy() {
_handler.unsubscribeAll();
- $(document.body).unbind("mousedown", handleBodyMouseDown);
+ $(document.body).off("mousedown", handleBodyMouseDown);
}
@@ -149,7 +149,7 @@
}
$el
- .bind("click", showMenu)
+ .on("click", showMenu)
.appendTo(args.node);
}
}
@@ -195,7 +195,7 @@
.data("command", item.command || '')
.data("column", columnDef)
.data("item", item)
- .bind("click", handleMenuItemClick)
+ .on("click", handleMenuItemClick)
.appendTo($menu);
if (item.disabled) {
diff --git a/web/pgadmin/static/vendor/slickgrid/plugins/slick.rowselectionmodel.js b/web/pgadmin/static/vendor/slickgrid/plugins/slick.rowselectionmodel.js
index 190b0f71..8553d050 100644
--- a/web/pgadmin/static/vendor/slickgrid/plugins/slick.rowselectionmodel.js
+++ b/web/pgadmin/static/vendor/slickgrid/plugins/slick.rowselectionmodel.js
@@ -121,8 +121,8 @@
if (active >= 0 && active < _grid.getDataLength()) {
_grid.scrollRowIntoView(active);
- _ranges = rowsToRanges(getRowsRange(top, bottom));
- setSelectedRanges(_ranges);
+ var tempRanges = rowsToRanges(getRowsRange(top, bottom));
+ setSelectedRanges(tempRanges);
}
e.preventDefault();
@@ -166,8 +166,8 @@
_grid.setActiveCell(cell.row, cell.cell);
}
- _ranges = rowsToRanges(selection);
- setSelectedRanges(_ranges);
+ var tempRanges = rowsToRanges(selection);
+ setSelectedRanges(tempRanges);
e.stopImmediatePropagation();
return true;
diff --git a/web/pgadmin/static/vendor/slickgrid/slick-default-theme.css b/web/pgadmin/static/vendor/slickgrid/slick-default-theme.css
index 2338d6e7..efc74154 100644
--- a/web/pgadmin/static/vendor/slickgrid/slick-default-theme.css
+++ b/web/pgadmin/static/vendor/slickgrid/slick-default-theme.css
@@ -29,23 +29,23 @@ classes should alter those!
height: 100%;
}
-.sr.ui-state-active {
+.slick-row.ui-state-active {
background: #F5F7D7;
}
-.sr {
+.slick-row {
position: absolute;
background: white;
border: 0px;
line-height: 20px;
}
-.sr.selected {
+.slick-row.selected {
z-index: 10;
background: #DFE8F6;
}
-.sc {
+.slick-cell {
padding-left: 4px;
padding-right: 4px;
}
@@ -73,11 +73,11 @@ classes should alter those!
background: white;
}
-.sc.selected {
+.slick-cell.selected {
background-color: beige;
}
-.sc.active {
+.slick-cell.active {
border-color: gray;
border-style: solid;
}
@@ -86,25 +86,25 @@ classes should alter those!
background: silver !important;
}
-.sr.odd {
+.slick-row.odd {
background: #fafafa;
}
-.sr.ui-state-active {
+.slick-row.ui-state-active {
background: #F5F7D7;
}
-.sr.loading {
+.slick-row.loading {
opacity: 0.5;
filter: alpha(opacity = 50);
}
-.sc.invalid {
+.slick-cell.invalid {
border-color: red;
-moz-animation-duration: 0.2s;
-webkit-animation-duration: 0.2s;
-moz-animation-name: slickgrid-invalid-hilite;
- -webkit-animation-name: slickgrid-invalid-hilite;
+ -webkit-animation-name: slickgrid-invalid-hilite;
}
@-moz-keyframes slickgrid-invalid-hilite {
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.core.js b/web/pgadmin/static/vendor/slickgrid/slick.core.js
index c4f04ec4..1846a50a 100644
--- a/web/pgadmin/static/vendor/slickgrid/slick.core.js
+++ b/web/pgadmin/static/vendor/slickgrid/slick.core.js
@@ -40,7 +40,8 @@
RIGHT: 39,
TAB: 9,
UP: 38
- }
+ },
+ "preClickClassName" : "slick-edit-preclick"
}
});
@@ -423,7 +424,7 @@
/***
* Sets the specified edit controller as the active edit controller (acquire edit lock).
- * If another edit controller is already active, and exception will be thrown.
+ * If another edit controller is already active, and exception will be throw new Error(.
* @method activate
* @param editController {EditController} edit controller acquiring the lock
*/
@@ -432,26 +433,26 @@
return;
}
if (activeEditController !== null) {
- throw "SlickGrid.EditorLock.activate: an editController is still active, can't activate another editController";
+ throw new Error("SlickGrid.EditorLock.activate: an editController is still active, can't activate another editController");
}
if (!editController.commitCurrentEdit) {
- throw "SlickGrid.EditorLock.activate: editController must implement .commitCurrentEdit()";
+ throw new Error("SlickGrid.EditorLock.activate: editController must implement .commitCurrentEdit()");
}
if (!editController.cancelCurrentEdit) {
- throw "SlickGrid.EditorLock.activate: editController must implement .cancelCurrentEdit()";
+ throw new Error("SlickGrid.EditorLock.activate: editController must implement .cancelCurrentEdit()");
}
activeEditController = editController;
};
/***
* Unsets the specified edit controller as the active edit controller (release edit lock).
- * If the specified edit controller is not the active one, an exception will be thrown.
+ * If the specified edit controller is not the active one, an exception will be throw new Error(.
* @method deactivate
* @param editController {EditController} edit controller releasing the lock
*/
this.deactivate = function (editController) {
if (activeEditController !== editController) {
- throw "SlickGrid.EditorLock.deactivate: specified editController is not the currently active one";
+ throw new Error("SlickGrid.EditorLock.deactivate: specified editController is not the currently active one");
}
activeEditController = null;
};
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.dataview.js b/web/pgadmin/static/vendor/slickgrid/slick.dataview.js
index f62df669..b004b800 100644
--- a/web/pgadmin/static/vendor/slickgrid/slick.dataview.js
+++ b/web/pgadmin/static/vendor/slickgrid/slick.dataview.js
@@ -107,7 +107,7 @@
for (var i = startingIndex, l = items.length; i < l; i++) {
id = items[i][idProperty];
if (id === undefined) {
- throw "Each data element must implement a unique 'id' property";
+ throw new Error("Each data element must implement a unique 'id' property");
}
idxById[id] = i;
}
@@ -118,7 +118,7 @@
for (var i = 0, l = items.length; i < l; i++) {
id = items[i][idProperty];
if (id === undefined || idxById[id] !== i) {
- throw "Each data element must implement a unique 'id' property";
+ throw new Error("Each data element must implement a unique 'id' property");
}
}
}
@@ -210,6 +210,15 @@
}
}
+ function getFilteredItems(){
+ return filteredItems;
+ }
+
+
+ function getFilter(){
+ return filter;
+ }
+
function setFilter(filterFn) {
filter = filterFn;
if (options.inlineFilters) {
@@ -330,7 +339,7 @@
function updateItem(id, item) {
if (idxById[id] === undefined || id !== item[idProperty]) {
- throw "Invalid or non-matching id";
+ throw new Error("Invalid or non-matching id");
}
items[idxById[id]] = item;
if (!updated) {
@@ -355,7 +364,7 @@
function deleteItem(id) {
var idx = idxById[id];
if (idx === undefined) {
- throw "Invalid id";
+ throw new Error("Invalid id");
}
delete idxById[id];
items.splice(idx, 1);
@@ -516,7 +525,7 @@
group = groups[i];
group.groups = extractGroups(group.rows, group);
}
- }
+ }
groups.sort(groupingInfos[level].comparer);
@@ -566,7 +575,7 @@
level = level || 0;
var gi = groupingInfos[level];
var groupCollapsed = gi.collapsed;
- var toggledGroups = toggledGroupsByLevel[level];
+ var toggledGroups = toggledGroupsByLevel[level];
var idx = groups.length, g;
while (idx--) {
g = groups[idx];
@@ -588,7 +597,7 @@
g.collapsed = groupCollapsed ^ toggledGroups[g.groupingKey];
g.title = gi.formatter ? gi.formatter(g) : g.value;
}
- }
+ }
function flattenGroupedRows(groups, level) {
level = level || 0;
@@ -762,14 +771,17 @@
// get the current page
var paged;
if (pagesize) {
- if (filteredItems.length < pagenum * pagesize) {
- pagenum = Math.floor(filteredItems.length / pagesize);
+ if (filteredItems.length <= pagenum * pagesize) {
+ if (filteredItems.length === 0) {
+ pagenum = 0;
+ } else {
+ pagenum = Math.floor((filteredItems.length - 1) / pagesize);
+ }
}
paged = filteredItems.slice(pagesize * pagenum, pagesize * pagenum + pagesize);
} else {
paged = filteredItems;
}
-
return {totalRows: filteredItems.length, rows: paged};
}
@@ -916,7 +928,7 @@
inHandler = true;
var selectedRows = self.mapIdsToRows(selectedRowIds);
if (!preserveHidden) {
- setSelectedRowIds(self.mapRowsToIds(selectedRows));
+ setSelectedRowIds(self.mapRowsToIds(selectedRows));
}
grid.setSelectedRows(selectedRows);
inHandler = false;
@@ -980,6 +992,10 @@
if (key != args.key) { return; }
if (args.hash) {
storeCellCssStyles(args.hash);
+ } else {
+ grid.onCellCssStylesChanged.unsubscribe(styleChanged);
+ self.onRowsChanged.unsubscribe(update);
+ self.onRowCountChanged.unsubscribe(update);
}
});
@@ -997,6 +1013,8 @@
"getItems": getItems,
"setItems": setItems,
"setFilter": setFilter,
+ "getFilter": getFilter,
+ "getFilteredItems": getFilteredItems,
"sort": sort,
"fastSort": fastSort,
"reSort": reSort,
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.editors.js b/web/pgadmin/static/vendor/slickgrid/slick.editors.js
index e852592c..33b4e266 100644
--- a/web/pgadmin/static/vendor/slickgrid/slick.editors.js
+++ b/web/pgadmin/static/vendor/slickgrid/slick.editors.js
@@ -11,7 +11,7 @@
"Editors": {
"Text": TextEditor,
"Integer": IntegerEditor,
- "Float": FloatEditor,
+ "Float": FloatEditor,
"Date": DateEditor,
"YesNoSelect": YesNoSelectEditor,
"Checkbox": CheckboxEditor,
@@ -29,7 +29,7 @@
this.init = function () {
$input = $("<INPUT type=text class='editor-text' />")
.appendTo(args.container)
- .bind("keydown.nav", function (e) {
+ .on("keydown.nav", function (e) {
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
e.stopImmediatePropagation();
}
@@ -98,7 +98,7 @@
this.init = function () {
$input = $("<INPUT type=text class='editor-text' />");
- $input.bind("keydown.nav", function (e) {
+ $input.on("keydown.nav", function (e) {
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
e.stopImmediatePropagation();
}
@@ -167,7 +167,7 @@
this.init = function () {
$input = $("<INPUT type=text class='editor-text' />");
- $input.bind("keydown.nav", function (e) {
+ $input.on("keydown.nav", function (e) {
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
e.stopImmediatePropagation();
}
@@ -185,24 +185,24 @@
$input.focus();
};
- function getDecimalPlaces() {
- // returns the number of fixed decimal places or null
- var rtn = args.column.editorFixedDecimalPlaces;
- if (typeof rtn == 'undefined') {
- rtn = FloatEditor.DefaultDecimalPlaces;
- }
- return (!rtn && rtn!==0 ? null : rtn);
- }
+ function getDecimalPlaces() {
+ // returns the number of fixed decimal places or null
+ var rtn = args.column.editorFixedDecimalPlaces;
+ if (typeof rtn == 'undefined') {
+ rtn = FloatEditor.DefaultDecimalPlaces;
+ }
+ return (!rtn && rtn!==0 ? null : rtn);
+ }
this.loadValue = function (item) {
defaultValue = item[args.column.field];
- var decPlaces = getDecimalPlaces();
- if (decPlaces !== null
- && (defaultValue || defaultValue===0)
- && defaultValue.toFixed) {
- defaultValue = defaultValue.toFixed(decPlaces);
- }
+ var decPlaces = getDecimalPlaces();
+ if (decPlaces !== null
+ && (defaultValue || defaultValue===0)
+ && defaultValue.toFixed) {
+ defaultValue = defaultValue.toFixed(decPlaces);
+ }
$input.val(defaultValue);
$input[0].defaultValue = defaultValue;
@@ -210,14 +210,14 @@
};
this.serializeValue = function () {
- var rtn = parseFloat($input.val()) || 0;
+ var rtn = parseFloat($input.val()) || 0;
- var decPlaces = getDecimalPlaces();
- if (decPlaces !== null
- && (rtn || rtn===0)
- && rtn.toFixed) {
- rtn = parseFloat(rtn.toFixed(decPlaces));
- }
+ var decPlaces = getDecimalPlaces();
+ if (decPlaces !== null
+ && (rtn || rtn===0)
+ && rtn.toFixed) {
+ rtn = parseFloat(rtn.toFixed(decPlaces));
+ }
return rtn;
};
@@ -269,8 +269,7 @@
$input.datepicker({
showOn: "button",
buttonImageOnly: true,
- buttonImage: "../images/calendar.gif",
- beforeShow: function () {
+ beforeShow: function () {
calendarOpen = true
},
onClose: function () {
@@ -422,6 +421,10 @@
}
};
+ this.preClick = function () {
+ $select.prop('checked', !$select.prop('checked'));
+ };
+
this.serializeValue = function () {
return $select.prop('checked');
};
@@ -470,7 +473,7 @@
}
});
- $picker.find(".editor-percentcomplete-buttons button").bind("click", function (e) {
+ $picker.find(".editor-percentcomplete-buttons button").on("click", function (e) {
$input.val($(this).attr("val"));
$picker.find(".editor-percentcomplete-slider").slider("value", $(this).attr("val"));
})
@@ -535,15 +538,15 @@
$wrapper = $("<DIV style='z-index:10000;position:absolute;background:white;padding:5px;border:3px solid gray; -moz-border-radius:10px; border-radius:10px;'/>")
.appendTo($container);
- $input = $("<TEXTAREA hidefocus rows=5 style='backround:white;width:250px;height:80px;border:0;outline:0'>")
+ $input = $("<TEXTAREA hidefocus rows=5 style='background:white;width:250px;height:80px;border:0;outline:0'>")
.appendTo($wrapper);
$("<DIV style='text-align:right'><BUTTON>Save</BUTTON><BUTTON>Cancel</BUTTON></DIV>")
.appendTo($wrapper);
- $wrapper.find("button:first").bind("click", this.save);
- $wrapper.find("button:last").bind("click", this.cancel);
- $input.bind("keydown", this.handleKeyDown);
+ $wrapper.find("button:first").on("click", this.save);
+ $wrapper.find("button:last").on("click", this.cancel);
+ $input.on("keydown", this.handleKeyDown);
scope.position(args.position);
$input.focus().select();
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.formatters.js b/web/pgadmin/static/vendor/slickgrid/slick.formatters.js
index 302b6f31..62bb8870 100644
--- a/web/pgadmin/static/vendor/slickgrid/slick.formatters.js
+++ b/web/pgadmin/static/vendor/slickgrid/slick.formatters.js
@@ -1,9 +1,9 @@
/***
* Contains basic SlickGrid formatters.
- *
+ *
* NOTE: These are merely examples. You will most likely need to implement something more
* robust/extensible/localizable/etc. for your use!
- *
+ *
* @module Formatters
* @namespace Slick
*/
@@ -16,7 +16,9 @@
"PercentComplete": PercentCompleteFormatter,
"PercentCompleteBar": PercentCompleteBarFormatter,
"YesNo": YesNoFormatter,
- "Checkmark": CheckmarkFormatter
+ "Checkmark": CheckmarkFormatter,
+ "Checkbox": CheckboxFormatter
+
}
}
});
@@ -53,6 +55,10 @@
return value ? "Yes" : "No";
}
+ function CheckboxFormatter(row, cell, value, columnDef, dataContext) {
+ return '<img class="slick-edit-preclick" src="../images/' + (value ? "CheckboxY" : "CheckboxN") + '.png">';
+ }
+
function CheckmarkFormatter(row, cell, value, columnDef, dataContext) {
return value ? "<img src='../images/tick.png'>" : "";
}
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.grid.css b/web/pgadmin/static/vendor/slickgrid/slick.grid.css
index a628c029..ce085eff 100644
--- a/web/pgadmin/static/vendor/slickgrid/slick.grid.css
+++ b/web/pgadmin/static/vendor/slickgrid/slick.grid.css
@@ -5,13 +5,13 @@ No built-in (selected, editable, highlight, flashing, invalid, loading, :focus)
classes should alter those!
*/
-.slick-header.ui-state-default, .slick-headerrow.ui-state-default {
+.slick-header.ui-state-default, .slick-headerrow.ui-state-default, .slick-footerrow.ui-state-default {
width: 100%;
overflow: hidden;
border-left: 0px !important;
}
-.slick-header-columns, .slick-headerrow-columns {
+.slick-header-columns, .slick-headerrow-columns, .slick-footerrow-columns {
position: relative;
white-space: nowrap;
cursor: default;
@@ -21,7 +21,7 @@ classes should alter those!
.slick-header-column.ui-state-default {
position: relative;
display: inline-block;
- /*box-sizing: content-box !important; */
+ /*box-sizing: content-box !important; use this for Firefox! */
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
@@ -36,7 +36,7 @@ classes should alter those!
float: left;
}
-.slick-headerrow-column.ui-state-default {
+.slick-headerrow-column.ui-state-default, .slick-footerrow-column.ui-state-default {
padding: 4px;
}
@@ -53,6 +53,21 @@ classes should alter those!
float: left;
}
+.slick-sort-indicator-numbered {
+ display: inline-block;
+ width: 8px;
+ height: 5px;
+ margin-left: 4px;
+ margin-top: 0;
+ padding-left: 1px;
+ line-height: 20px;
+ float: left;
+ font-family: Arial;
+ font-style: normal;
+ font-weight: bold;
+ color: #6190CD;
+}
+
.slick-sort-indicator-desc {
background: url(images/sort-desc.gif);
}
@@ -81,13 +96,13 @@ classes should alter those!
outline: 0;
}
-.sr.ui-widget-content, .sr.ui-state-active {
+.slick-row.ui-widget-content, .slick-row.ui-state-active {
position: absolute;
border: 0px;
width: 100%;
}
-.sc, .slick-headerrow-column {
+.slick-cell, .slick-headerrow-column , .slick-footerrow-column{
position: absolute;
border: 1px solid transparent;
border-right: 1px dotted silver;
@@ -102,7 +117,13 @@ classes should alter those!
white-space: nowrap;
cursor: default;
}
-
+.slick-cell, .slick-headerrow-column{
+ border-bottom-color: silver;
+}
+.slick-footerrow-column {
+ border-top-color: silver;
+}
+
.slick-group {
}
@@ -110,7 +131,7 @@ classes should alter those!
display: inline-block;
}
-.sc.highlighted {
+.slick-cell.highlighted {
background: lightskyblue;
background: rgba(0, 0, 255, 0.2);
-webkit-transition: all 0.5s;
@@ -119,11 +140,11 @@ classes should alter those!
transition: all 0.5s;
}
-.sc.flashing {
+.slick-cell.flashing {
border: 1px solid red !important;
}
-.sc.editable {
+.slick-cell.editable {
z-index: 11;
overflow: visible;
background: white;
@@ -131,7 +152,7 @@ classes should alter those!
border-style: solid;
}
-.sc:focus {
+.slick-cell:focus {
outline: none;
}
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.grid.js b/web/pgadmin/static/vendor/slickgrid/slick.grid.js
index 29d07e4f..9fee5816 100644
--- a/web/pgadmin/static/vendor/slickgrid/slick.grid.js
+++ b/web/pgadmin/static/vendor/slickgrid/slick.grid.js
@@ -1,3607 +1,3768 @@
-/**
- * @license
- * (c) 2009-2013 Michael Leibman
- * michael{dot}leibman{at}gmail{dot}com
- * http://github.com/mleibman/slickgrid
- *
- * Distributed under MIT license.
- * All rights reserved.
- *
- * SlickGrid v2.2
- *
- * NOTES:
- * Cell/row DOM manipulations are done directly bypassing jQuery's DOM manipulation methods.
- * This increases the speed dramatically, but can only be done safely because there are no event handlers
- * or data associated with any cell/row DOM nodes. Cell editors must make sure they implement .destroy()
- * and do proper cleanup.
- */
-
-// make sure required JavaScript modules are loaded
-if (typeof jQuery === "undefined") {
- throw "SlickGrid requires jquery module to be loaded";
-}
-if (!jQuery.fn.drag) {
- throw "SlickGrid requires jquery.event.drag module to be loaded";
-}
-if (typeof Slick === "undefined") {
- throw "slick.core.js not loaded";
-}
-
-
-(function ($) {
- // Slick.Grid
- $.extend(true, window, {
- Slick: {
- Grid: SlickGrid
- }
- });
-
- // shared across all grids on the page
- var scrollbarDimensions;
- var maxSupportedCssHeight; // browser's breaking point
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // SlickGrid class implementation (available as Slick.Grid)
-
- /**
- * Creates a new instance of the grid.
- * @class SlickGrid
- * @constructor
- * @param {Node} container Container node to create the grid in.
- * @param {Array,Object} data An array of objects for databinding.
- * @param {Array} columns An array of column definitions.
- * @param {Object} options Grid options.
- **/
- function SlickGrid(container, data, columns, options) {
- // settings
- var defaults = {
- explicitInitialization: false,
- rowHeight: 25,
- defaultColumnWidth: 80,
- enableAddRow: false,
- leaveSpaceForNewRows: false,
- editable: false,
- autoEdit: true,
- enableCellNavigation: true,
- enableColumnReorder: true,
- asyncEditorLoading: false,
- asyncEditorLoadDelay: 100,
- forceFitColumns: false,
- enableAsyncPostRender: false,
- asyncPostRenderDelay: 50,
- enableAsyncPostRenderCleanup: false,
- asyncPostRenderCleanupDelay: 40,
- autoHeight: false,
- editorLock: Slick.GlobalEditorLock,
- showHeaderRow: false,
- headerRowHeight: 25,
- showTopPanel: false,
- topPanelHeight: 25,
- formatterFactory: null,
- editorFactory: null,
- cellFlashingCssClass: "flashing",
- selectedCellCssClass: "selected",
- multiSelect: true,
- enableTextSelectionOnCells: false,
- dataItemColumnValueExtractor: null,
- fullWidthRows: false,
- multiColumnSort: false,
- defaultFormatter: defaultFormatter,
- forceSyncScrolling: false,
- addNewRowCssClass: "new-row"
- };
-
- var columnDefaults = {
- name: "",
- resizable: true,
- sortable: false,
- minWidth: 30,
- rerenderOnResize: false,
- headerCssClass: null,
- defaultSortAsc: true,
- focusable: true,
- selectable: true
- };
-
- // scroller
- var th; // virtual height
- var h; // real scrollable height
- var ph; // page height
- var n; // number of pages
- var cj; // "jumpiness" coefficient
-
- var page = 0; // current page
- var offset = 0; // current page offset
- var vScrollDir = 1;
-
- // private
- var initialized = false;
- var $container;
- var uid = "slickgrid_" + Math.round(1000000 * Math.random());
- var self = this;
- var $focusSink, $focusSink2;
- var $headerScroller;
- var $headers;
- var $headerRow, $headerRowScroller, $headerRowSpacer;
- var $topPanelScroller;
- var $topPanel;
- var $viewport;
- var $canvas;
- var $style;
- var $boundAncestors;
- var stylesheet, columnCssRulesL, columnCssRulesR;
- var viewportH, viewportW;
- var canvasWidth;
- var viewportHasHScroll, viewportHasVScroll;
- var headerColumnWidthDiff = 0, headerColumnHeightDiff = 0, // border+padding
- cellWidthDiff = 0, cellHeightDiff = 0, jQueryNewWidthBehaviour = false;
- var absoluteColumnMinWidth;
-
- var tabbingDirection = 1;
- var activePosX;
- var activeRow, activeCell;
- var activeCellNode = null;
- var currentEditor = null;
- var serializedEditorValue;
- var editController;
-
- var rowsCache = {};
- var renderedRows = 0;
- var numVisibleRows;
- var prevScrollTop = 0;
- var scrollTop = 0;
- var lastRenderedScrollTop = 0;
- var lastRenderedScrollLeft = 0;
- var prevScrollLeft = 0;
- var scrollLeft = 0;
-
- var selectionModel;
- var selectedRows = [];
-
- var plugins = [];
- var cellCssClasses = {};
-
- var columnsById = {};
- var sortColumns = [];
- var columnPosLeft = [];
- var columnPosRight = [];
-
-
- // async call handles
- var h_editorLoader = null;
- var h_render = null;
- var h_postrender = null;
- var h_postrenderCleanup = null;
- var postProcessedRows = {};
- var postProcessToRow = null;
- var postProcessFromRow = null;
- var postProcessedCleanupQueue = [];
- var postProcessgroupId = 0;
-
- // perf counters
- var counter_rows_rendered = 0;
- var counter_rows_removed = 0;
-
- // These two variables work around a bug with inertial scrolling in Webkit/Blink on Mac.
- // See http://crbug.com/312427.
- var rowNodeFromLastMouseWheelEvent; // this node must not be deleted while inertial scrolling
- var zombieRowNodeFromLastMouseWheelEvent; // node that was hidden instead of getting deleted
- var zombieRowCacheFromLastMouseWheelEvent; // row cache for above node
- var zombieRowPostProcessedFromLastMouseWheelEvent; // post processing references for above node
-
- // store css attributes if display:none is active in container or parent
- var cssShow = { position: 'absolute', visibility: 'hidden', display: 'block' };
- var $hiddenParents;
- var oldProps = [];
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Initialization
-
- function init() {
- $container = $(container);
- if ($container.length < 1) {
- throw new Error("SlickGrid requires a valid container, " + container + " does not exist in the DOM.");
- }
-
- cacheCssForHiddenInit();
-
- // calculate these only once and share between grid instances
- maxSupportedCssHeight = maxSupportedCssHeight || getMaxSupportedCssHeight();
- scrollbarDimensions = scrollbarDimensions || measureScrollbar();
-
- options = $.extend({}, defaults, options);
- validateAndEnforceOptions();
- columnDefaults.width = options.defaultColumnWidth;
-
- columnsById = {};
- for (var i = 0; i < columns.length; i++) {
- var m = columns[i] = $.extend({}, columnDefaults, columns[i]);
- columnsById[m.id] = i;
- if (m.minWidth && m.width < m.minWidth) {
- m.width = m.minWidth;
- }
- if (m.maxWidth && m.width > m.maxWidth) {
- m.width = m.maxWidth;
- }
- }
-
- // validate loaded JavaScript modules against requested options
- if (options.enableColumnReorder && !$.fn.sortable) {
- throw new Error("SlickGrid's 'enableColumnReorder = true' option requires jquery-ui.sortable module to be loaded");
- }
-
- editController = {
- "commitCurrentEdit": commitCurrentEdit,
- "cancelCurrentEdit": cancelCurrentEdit
- };
-
- $container
- .empty()
- .css("overflow", "hidden")
- .css("outline", 0)
- .addClass(uid)
- .addClass("ui-widget");
-
- // set up a positioning container if needed
- if (!/relative|absolute|fixed/.test($container.css("position"))) {
- $container.css("position", "relative");
- }
-
- $focusSink = $("<div tabIndex='0' hideFocus style='position:fixed;width:0;height:0;top:0;left:0;outline:0;'></div>").appendTo($container);
-
- $headerScroller = $("<div class='slick-header ui-state-default' style='overflow:hidden;position:relative;' />").appendTo($container);
- $headers = $("<div class='slick-header-columns' style='left:-1000px' />").appendTo($headerScroller);
- $headers.width(getHeadersWidth());
-
- $headerRowScroller = $("<div class='slick-headerrow ui-state-default' style='overflow:hidden;position:relative;' />").appendTo($container);
- $headerRow = $("<div class='slick-headerrow-columns' />").appendTo($headerRowScroller);
- $headerRowSpacer = $("<div style='display:block;height:1px;position:absolute;top:0;left:0;'></div>")
- .css("width", getCanvasWidth() + scrollbarDimensions.width + "px")
- .appendTo($headerRowScroller);
-
- $topPanelScroller = $("<div class='slick-top-panel-scroller ui-state-default' style='overflow:hidden;position:relative;' />").appendTo($container);
- $topPanel = $("<div class='slick-top-panel' style='width:10000px' />").appendTo($topPanelScroller);
-
- if (!options.showTopPanel) {
- $topPanelScroller.hide();
- }
-
- if (!options.showHeaderRow) {
- $headerRowScroller.hide();
- }
-
- $viewport = $("<div class='slick-viewport' style='width:100%;overflow:auto;outline:0;position:relative;;'>").appendTo($container);
- $viewport.css("overflow-y", options.autoHeight ? "hidden" : "auto");
-
- $canvas = $("<div class='grid-canvas' />").appendTo($viewport);
-
- $focusSink2 = $focusSink.clone().appendTo($container);
-
- if (!options.explicitInitialization) {
- finishInitialization();
- }
- }
-
- function finishInitialization() {
- if (!initialized) {
- initialized = true;
-
- viewportW = parseFloat($.css($container[0], "width", true));
-
- // header columns and cells may have different padding/border skewing width calculations (box-sizing, hello?)
- // calculate the diff so we can set consistent sizes
- measureCellPaddingAndBorder();
-
- // for usability reasons, all text selection in SlickGrid is disabled
- // with the exception of input and textarea elements (selection must
- // be enabled there so that editors work as expected); note that
- // selection in grid cells (grid body) is already unavailable in
- // all browsers except IE
- disableSelection($headers); // disable all text selection in header (including input and textarea)
-
- if (!options.enableTextSelectionOnCells) {
- // disable text selection in grid cells except in input and textarea elements
- // (this is IE-specific, because selectstart event will only fire in IE)
- $viewport.bind("selectstart.ui", function (event) {
- return $(event.target).is("input,textarea");
- });
- }
-
- updateColumnCaches();
- createColumnHeaders();
- setupColumnSort();
- createCssRules();
- resizeCanvas();
- bindAncestorScrollEvents();
-
- $container
- .bind("resize.slickgrid", resizeCanvas);
- $viewport
- //.bind("click", handleClick)
- .bind("scroll", handleScroll);
- $headerScroller
- .bind("contextmenu", handleHeaderContextMenu)
- .bind("click", handleHeaderClick)
- .delegate(".slick-header-column", "mouseenter", handleHeaderMouseEnter)
- .delegate(".slick-header-column", "mouseleave", handleHeaderMouseLeave);
- $headerRowScroller
- .bind("scroll", handleHeaderRowScroll);
- $focusSink.add($focusSink2)
- .bind("keydown", handleKeyDown);
- $canvas
- .bind("keydown", handleKeyDown)
- .bind("click", handleClick)
- .bind("dblclick", handleDblClick)
- .bind("contextmenu", handleContextMenu)
- .bind("draginit", handleDragInit)
- .bind("dragstart", {distance: 3}, handleDragStart)
- .bind("drag", handleDrag)
- .bind("dragend", handleDragEnd)
- .delegate(".sc", "mouseenter", handleMouseEnter)
- .delegate(".sc", "mouseleave", handleMouseLeave);
-
- // Work around http://crbug.com/312427.
- if (navigator.userAgent.toLowerCase().match(/webkit/) &&
- navigator.userAgent.toLowerCase().match(/macintosh/)) {
- $canvas.bind("mousewheel", handleMouseWheel);
- }
- restoreCssFromHiddenInit();
- }
- }
-
- function cacheCssForHiddenInit() {
- // handle display:none on container or container parents
- $hiddenParents = $container.parents().andSelf().not(':visible');
- $hiddenParents.each(function() {
- var old = {};
- for ( var name in cssShow ) {
- old[ name ] = this.style[ name ];
- this.style[ name ] = cssShow[ name ];
- }
- oldProps.push(old);
- });
- }
-
- function restoreCssFromHiddenInit() {
- // finish handle display:none on container or container parents
- // - put values back the way they were
- $hiddenParents.each(function(i) {
- var old = oldProps[i];
- for ( var name in cssShow ) {
- this.style[ name ] = old[ name ];
- }
- });
- }
-
- function registerPlugin(plugin) {
- plugins.unshift(plugin);
- plugin.init(self);
- }
-
- function unregisterPlugin(plugin) {
- for (var i = plugins.length; i >= 0; i--) {
- if (plugins[i] === plugin) {
- if (plugins[i].destroy) {
- plugins[i].destroy();
- }
- plugins.splice(i, 1);
- break;
- }
- }
- }
-
- function setSelectionModel(model) {
- if (selectionModel) {
- selectionModel.onSelectedRangesChanged.unsubscribe(handleSelectedRangesChanged);
- if (selectionModel.destroy) {
- selectionModel.destroy();
- }
- }
-
- selectionModel = model;
- if (selectionModel) {
- selectionModel.init(self);
- selectionModel.onSelectedRangesChanged.subscribe(handleSelectedRangesChanged);
- }
- }
-
- function getSelectionModel() {
- return selectionModel;
- }
-
- function getCanvasNode() {
- return $canvas[0];
- }
-
- function measureScrollbar() {
- var $c = $("<div style='position:absolute; top:-10000px; left:-10000px; width:100px; height:100px; overflow:scroll;'></div>").appendTo("body");
- var dim = {
- width: $c.width() - $c[0].clientWidth,
- height: $c.height() - $c[0].clientHeight
- };
- $c.remove();
- return dim;
- }
-
- function getHeadersWidth() {
- var headersWidth = 0;
- for (var i = 0, ii = columns.length; i < ii; i++) {
- var width = columns[i].width;
- headersWidth += width;
- }
- headersWidth += scrollbarDimensions.width;
- return Math.max(headersWidth, viewportW) + 1000;
- }
-
- function getCanvasWidth() {
- var availableWidth = viewportHasVScroll ? viewportW - scrollbarDimensions.width : viewportW;
- var rowWidth = 0;
- var i = columns.length;
- while (i--) {
- rowWidth += columns[i].width;
- }
- return options.fullWidthRows ? Math.max(rowWidth, availableWidth) : rowWidth;
- }
-
- function updateCanvasWidth(forceColumnWidthsUpdate) {
- var oldCanvasWidth = canvasWidth;
- canvasWidth = getCanvasWidth();
-
- if (canvasWidth != oldCanvasWidth) {
- $canvas.width(canvasWidth);
- $headerRow.width(canvasWidth);
- $headers.width(getHeadersWidth());
- viewportHasHScroll = (canvasWidth > viewportW - scrollbarDimensions.width);
- }
-
- $headerRowSpacer.width(canvasWidth + (viewportHasVScroll ? scrollbarDimensions.width : 0));
-
- if (canvasWidth != oldCanvasWidth || forceColumnWidthsUpdate) {
- applyColumnWidths();
- }
- }
-
- function disableSelection($target) {
- if ($target && $target.jquery) {
- $target
- .attr("unselectable", "on")
- .css("MozUserSelect", "none")
- .bind("selectstart.ui", function () {
- return false;
- }); // from jquery:ui.core.js 1.7.2
- }
- }
-
- function getMaxSupportedCssHeight() {
- var supportedHeight = 1000000;
- // FF reports the height back but still renders blank after ~6M px
- var testUpTo = navigator.userAgent.toLowerCase().match(/firefox/) ? 6000000 : 1000000000;
- var div = $("<div style='display:none' />").appendTo(document.body);
-
- while (true) {
- var test = supportedHeight * 2;
- div.css("height", test);
- if (test > testUpTo || div.height() !== test) {
- break;
- } else {
- supportedHeight = test;
- }
- }
-
- div.remove();
- return supportedHeight;
- }
-
- // TODO: this is static. need to handle page mutation.
- function bindAncestorScrollEvents() {
- var elem = $canvas[0];
- while ((elem = elem.parentNode) != document.body && elem != null) {
- // bind to scroll containers only
- if (elem == $viewport[0] || elem.scrollWidth != elem.clientWidth || elem.scrollHeight != elem.clientHeight) {
- var $elem = $(elem);
- if (!$boundAncestors) {
- $boundAncestors = $elem;
- } else {
- $boundAncestors = $boundAncestors.add($elem);
- }
- $elem.bind("scroll." + uid, handleActiveCellPositionChange);
- }
- }
- }
-
- function unbindAncestorScrollEvents() {
- if (!$boundAncestors) {
- return;
- }
- $boundAncestors.unbind("scroll." + uid);
- $boundAncestors = null;
- }
-
- function updateColumnHeader(columnId, title, toolTip) {
- if (!initialized) { return; }
- var idx = getColumnIndex(columnId);
- if (idx == null) {
- return;
- }
-
- var columnDef = columns[idx];
- var $header = $headers.children().eq(idx);
- if ($header) {
- if (title !== undefined) {
- columns[idx].name = title;
- }
- if (toolTip !== undefined) {
- columns[idx].toolTip = toolTip;
- }
-
- trigger(self.onBeforeHeaderCellDestroy, {
- "node": $header[0],
- "column": columnDef,
- "grid": self
- });
-
- $header
- .attr("title", toolTip || "")
- .children().eq(0).html(title);
-
- trigger(self.onHeaderCellRendered, {
- "node": $header[0],
- "column": columnDef,
- "grid": self
- });
- }
- }
-
- function getHeaderRow() {
- return $headerRow[0];
- }
-
- function getHeaderRowColumn(columnId) {
- var idx = getColumnIndex(columnId);
- var $header = $headerRow.children().eq(idx);
- return $header && $header[0];
- }
-
- function createColumnHeaders() {
- function onMouseEnter() {
- $(this).addClass("ui-state-hover");
- }
-
- function onMouseLeave() {
- $(this).removeClass("ui-state-hover");
- }
-
- $headers.find(".slick-header-column")
- .each(function() {
- var columnDef = $(this).data("column");
- if (columnDef) {
- trigger(self.onBeforeHeaderCellDestroy, {
- "node": this,
- "column": columnDef,
- "grid": self
- });
- }
- });
- $headers.empty();
- $headers.width(getHeadersWidth());
-
- $headerRow.find(".slick-headerrow-column")
- .each(function() {
- var columnDef = $(this).data("column");
- if (columnDef) {
- trigger(self.onBeforeHeaderRowCellDestroy, {
- "node": this,
- "column": columnDef,
- "grid": self
- });
- }
- });
- $headerRow.empty();
-
- for (var i = 0; i < columns.length; i++) {
- var m = columns[i];
-
- var header = $("<div class='ui-state-default slick-header-column' />")
- .html("<span class='slick-column-name'>" + m.name + "</span>")
- .width(m.width - headerColumnWidthDiff)
- .attr("id", "" + uid + m.id)
- .attr("title", m.toolTip || "")
- .data("column", m)
- .addClass(m.headerCssClass || "")
- .appendTo($headers);
-
- if (options.enableColumnReorder || m.sortable) {
- header
- .on('mouseenter', onMouseEnter)
- .on('mouseleave', onMouseLeave);
- }
-
- if (m.sortable) {
- header.addClass("slick-header-sortable");
- header.append("<span class='slick-sort-indicator' />");
- }
-
- trigger(self.onHeaderCellRendered, {
- "node": header[0],
- "column": m,
- "grid": self
- });
-
- if (options.showHeaderRow) {
- var headerRowCell = $("<div class='ui-state-default slick-headerrow-column l" + i + " r" + i + "'></div>")
- .data("column", m)
- .appendTo($headerRow);
-
- trigger(self.onHeaderRowCellRendered, {
- "node": headerRowCell[0],
- "column": m,
- "grid": self
- });
- }
- }
-
- setSortColumns(sortColumns);
- setupColumnResize();
- if (options.enableColumnReorder) {
- setupColumnReorder();
- }
- }
-
- function setupColumnSort() {
- $headers.click(function (e) {
- // temporary workaround for a bug in jQuery 1.7.1 (http://bugs.jquery.com/ticket/11328)
- e.metaKey = e.metaKey || e.ctrlKey;
-
- if ($(e.target).hasClass("slick-resizable-handle")) {
- return;
- }
-
- var $col = $(e.target).closest(".slick-header-column");
- if (!$col.length) {
- return;
- }
-
- var column = $col.data("column");
- if (column.sortable) {
- if (!getEditorLock().commitCurrentEdit()) {
- return;
- }
-
- var sortOpts = null;
- var i = 0;
- for (; i < sortColumns.length; i++) {
- if (sortColumns[i].columnId == column.id) {
- sortOpts = sortColumns[i];
- sortOpts.sortAsc = !sortOpts.sortAsc;
- break;
- }
- }
-
- if (e.metaKey && options.multiColumnSort) {
- if (sortOpts) {
- sortColumns.splice(i, 1);
- }
- }
- else {
- if ((!e.shiftKey && !e.metaKey) || !options.multiColumnSort) {
- sortColumns = [];
- }
-
- if (!sortOpts) {
- sortOpts = { columnId: column.id, sortAsc: column.defaultSortAsc };
- sortColumns.push(sortOpts);
- } else if (sortColumns.length == 0) {
- sortColumns.push(sortOpts);
- }
- }
-
- setSortColumns(sortColumns);
-
- if (!options.multiColumnSort) {
- trigger(self.onSort, {
- multiColumnSort: false,
- sortCol: column,
- sortAsc: sortOpts.sortAsc,
- grid: self}, e);
- } else {
- trigger(self.onSort, {
- multiColumnSort: true,
- sortCols: $.map(sortColumns, function(col) {
- return {sortCol: columns[getColumnIndex(col.columnId)], sortAsc: col.sortAsc };
- }),
- grid: self}, e);
- }
- }
- });
- }
-
- function setupColumnReorder() {
- $headers.filter(":ui-sortable").sortable("destroy");
- $headers.sortable({
- containment: "parent",
- distance: 3,
- axis: "x",
- cursor: "default",
- tolerance: "intersection",
- helper: "clone",
- placeholder: "slick-sortable-placeholder ui-state-default slick-header-column",
- start: function (e, ui) {
- ui.placeholder.width(ui.helper.outerWidth() - headerColumnWidthDiff);
- $(ui.helper).addClass("slick-header-column-active");
- },
- beforeStop: function (e, ui) {
- $(ui.helper).removeClass("slick-header-column-active");
- },
- stop: function (e) {
- if (!getEditorLock().commitCurrentEdit()) {
- $(this).sortable("cancel");
- return;
- }
-
- var reorderedIds = $headers.sortable("toArray");
- var reorderedColumns = [];
- for (var i = 0; i < reorderedIds.length; i++) {
- reorderedColumns.push(columns[getColumnIndex(reorderedIds[i].replace(uid, ""))]);
- }
- setColumns(reorderedColumns);
-
- trigger(self.onColumnsReordered, {grid: self});
- e.stopPropagation();
- setupColumnResize();
- }
- });
- }
-
- function setupColumnResize() {
- var $col, j, c, pageX, columnElements, minPageX, maxPageX, firstResizable, lastResizable;
- columnElements = $headers.children();
- columnElements.find(".slick-resizable-handle").remove();
- columnElements.each(function (i, e) {
- if (columns[i].resizable) {
- if (firstResizable === undefined) {
- firstResizable = i;
- }
- lastResizable = i;
- }
- });
- if (firstResizable === undefined) {
- return;
- }
- columnElements.each(function (i, e) {
- if (i < firstResizable || (options.forceFitColumns && i >= lastResizable)) {
- return;
- }
- $col = $(e);
- $("<div class='slick-resizable-handle' />")
- .appendTo(e)
- .bind("dragstart", function (e, dd) {
- if (!getEditorLock().commitCurrentEdit()) {
- return false;
- }
- pageX = e.pageX;
- $(this).parent().addClass("slick-header-column-active");
- var shrinkLeewayOnRight = null, stretchLeewayOnRight = null;
- // lock each column's width option to current width
- columnElements.each(function (i, e) {
- columns[i].previousWidth = $(e).outerWidth();
- });
- if (options.forceFitColumns) {
- shrinkLeewayOnRight = 0;
- stretchLeewayOnRight = 0;
- // colums on right affect maxPageX/minPageX
- for (j = i + 1; j < columnElements.length; j++) {
- c = columns[j];
- if (c.resizable) {
- if (stretchLeewayOnRight !== null) {
- if (c.maxWidth) {
- stretchLeewayOnRight += c.maxWidth - c.previousWidth;
- } else {
- stretchLeewayOnRight = null;
- }
- }
- shrinkLeewayOnRight += c.previousWidth - Math.max(c.minWidth || 0, absoluteColumnMinWidth);
- }
- }
- }
- var shrinkLeewayOnLeft = 0, stretchLeewayOnLeft = 0;
- for (j = 0; j <= i; j++) {
- // columns on left only affect minPageX
- c = columns[j];
- if (c.resizable) {
- if (stretchLeewayOnLeft !== null) {
- if (c.maxWidth) {
- stretchLeewayOnLeft += c.maxWidth - c.previousWidth;
- } else {
- stretchLeewayOnLeft = null;
- }
- }
- shrinkLeewayOnLeft += c.previousWidth - Math.max(c.minWidth || 0, absoluteColumnMinWidth);
- }
- }
- if (shrinkLeewayOnRight === null) {
- shrinkLeewayOnRight = 100000;
- }
- if (shrinkLeewayOnLeft === null) {
- shrinkLeewayOnLeft = 100000;
- }
- if (stretchLeewayOnRight === null) {
- stretchLeewayOnRight = 100000;
- }
- if (stretchLeewayOnLeft === null) {
- stretchLeewayOnLeft = 100000;
- }
- maxPageX = pageX + Math.min(shrinkLeewayOnRight, stretchLeewayOnLeft);
- minPageX = pageX - Math.min(shrinkLeewayOnLeft, stretchLeewayOnRight);
- })
- .bind("drag", function (e, dd) {
- var actualMinWidth, d = Math.min(maxPageX, Math.max(minPageX, e.pageX)) - pageX, x;
- if (d < 0) { // shrink column
- x = d;
- for (j = i; j >= 0; j--) {
- c = columns[j];
- if (c.resizable) {
- actualMinWidth = Math.max(c.minWidth || 0, absoluteColumnMinWidth);
- if (x && c.previousWidth + x < actualMinWidth) {
- x += c.previousWidth - actualMinWidth;
- c.width = actualMinWidth;
- } else {
- c.width = c.previousWidth + x;
- x = 0;
- }
- }
- }
-
- if (options.forceFitColumns) {
- x = -d;
- for (j = i + 1; j < columnElements.length; j++) {
- c = columns[j];
- if (c.resizable) {
- if (x && c.maxWidth && (c.maxWidth - c.previousWidth < x)) {
- x -= c.maxWidth - c.previousWidth;
- c.width = c.maxWidth;
- } else {
- c.width = c.previousWidth + x;
- x = 0;
- }
- }
- }
- }
- } else { // stretch column
- x = d;
- for (j = i; j >= 0; j--) {
- c = columns[j];
- if (c.resizable) {
- if (x && c.maxWidth && (c.maxWidth - c.previousWidth < x)) {
- x -= c.maxWidth - c.previousWidth;
- c.width = c.maxWidth;
- } else {
- c.width = c.previousWidth + x;
- x = 0;
- }
- }
- }
-
- if (options.forceFitColumns) {
- x = -d;
- for (j = i + 1; j < columnElements.length; j++) {
- c = columns[j];
- if (c.resizable) {
- actualMinWidth = Math.max(c.minWidth || 0, absoluteColumnMinWidth);
- if (x && c.previousWidth + x < actualMinWidth) {
- x += c.previousWidth - actualMinWidth;
- c.width = actualMinWidth;
- } else {
- c.width = c.previousWidth + x;
- x = 0;
- }
- }
- }
- }
- }
- applyColumnHeaderWidths();
- if (options.syncColumnCellResize) {
- applyColumnWidths();
- }
- })
- .bind("dragend", function (e, dd) {
- var newWidth;
- $(this).parent().removeClass("slick-header-column-active");
- for (j = 0; j < columnElements.length; j++) {
- c = columns[j];
- newWidth = $(columnElements[j]).outerWidth();
-
- if (c.previousWidth !== newWidth && c.rerenderOnResize) {
- invalidateAllRows();
- }
- }
- updateCanvasWidth(true);
- render();
- trigger(self.onColumnsResized, {grid: self});
- });
- });
- }
-
- function getVBoxDelta($el) {
- var p = ["borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom"];
- var delta = 0;
- $.each(p, function (n, val) {
- delta += parseFloat($el.css(val)) || 0;
- });
- return delta;
- }
-
- function measureCellPaddingAndBorder() {
- var el;
- var h = ["borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight"];
- var v = ["borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom"];
-
- // jquery prior to version 1.8 handles .width setter/getter as a direct css write/read
- // jquery 1.8 changed .width to read the true inner element width if box-sizing is set to border-box, and introduced a setter for .outerWidth
- // so for equivalent functionality, prior to 1.8 use .width, and after use .outerWidth
- var verArray = $.fn.jquery.split('.');
- jQueryNewWidthBehaviour = (verArray[0]==1 && verArray[1]>=8) || verArray[0] >=2;
-
- el = $("<div class='ui-state-default slick-header-column' style='visibility:hidden'>-</div>").appendTo($headers);
- headerColumnWidthDiff = headerColumnHeightDiff = 0;
- if (el.css("box-sizing") != "border-box" && el.css("-moz-box-sizing") != "border-box" && el.css("-webkit-box-sizing") != "border-box") {
- $.each(h, function (n, val) {
- headerColumnWidthDiff += parseFloat(el.css(val)) || 0;
- });
- $.each(v, function (n, val) {
- headerColumnHeightDiff += parseFloat(el.css(val)) || 0;
- });
- }
- el.remove();
-
- var r = $("<div class='sr' />").appendTo($canvas);
- el = $("<div class='sc' id='' style='visibility:hidden'>-</div>").appendTo(r);
- cellWidthDiff = cellHeightDiff = 0;
- if (el.css("box-sizing") != "border-box" && el.css("-moz-box-sizing") != "border-box" && el.css("-webkit-box-sizing") != "border-box") {
- $.each(h, function (n, val) {
- cellWidthDiff += parseFloat(el.css(val)) || 0;
- });
- $.each(v, function (n, val) {
- cellHeightDiff += parseFloat(el.css(val)) || 0;
- });
- }
- r.remove();
-
- absoluteColumnMinWidth = Math.max(headerColumnWidthDiff, cellWidthDiff);
- }
-
- function createCssRules() {
- $style = $("<style type='text/css' rel='stylesheet' />").appendTo($("head"));
- var rowHeight = (options.rowHeight - cellHeightDiff);
- var rules = [
- "." + uid + " .slick-header-column { left: 1000px; }",
- "." + uid + " .slick-top-panel { height:" + options.topPanelHeight + "px; }",
- "." + uid + " .slick-headerrow-columns { height:" + options.headerRowHeight + "px; }",
- "." + uid + " .sc { height:" + rowHeight + "px; }",
- "." + uid + " .sr { height:" + options.rowHeight + "px; }"
- ];
-
- for (var i = 0; i < columns.length; i++) {
- rules.push("." + uid + " .l" + i + " { }");
- rules.push("." + uid + " .r" + i + " { }");
- }
-
- if ($style[0].styleSheet) { // IE
- $style[0].styleSheet.cssText = rules.join(" ");
- } else {
- $style[0].appendChild(document.createTextNode(rules.join(" ")));
- }
- }
-
- function getColumnCssRules(idx) {
- if (!stylesheet) {
- var sheets = document.styleSheets;
- for (var i = 0; i < sheets.length; i++) {
- if ((sheets[i].ownerNode || sheets[i].owningElement) == $style[0]) {
- stylesheet = sheets[i];
- break;
- }
- }
-
- if (!stylesheet) {
- throw new Error("Cannot find stylesheet.");
- }
-
- // find and cache column CSS rules
- columnCssRulesL = [];
- columnCssRulesR = [];
- var cssRules = (stylesheet.cssRules || stylesheet.rules);
- var matches, columnIdx;
- for (var i = 0; i < cssRules.length; i++) {
- var selector = cssRules[i].selectorText;
- if (matches = /\.l\d+/.exec(selector)) {
- columnIdx = parseInt(matches[0].substr(2, matches[0].length - 2), 10);
- columnCssRulesL[columnIdx] = cssRules[i];
- } else if (matches = /\.r\d+/.exec(selector)) {
- columnIdx = parseInt(matches[0].substr(2, matches[0].length - 2), 10);
- columnCssRulesR[columnIdx] = cssRules[i];
- }
- }
- }
-
- return {
- "left": columnCssRulesL[idx],
- "right": columnCssRulesR[idx]
- };
- }
-
- function removeCssRules() {
- $style.remove();
- stylesheet = null;
- }
-
- function destroy() {
- getEditorLock().cancelCurrentEdit();
-
- trigger(self.onBeforeDestroy, {grid: self});
-
- var i = plugins.length;
- while(i--) {
- unregisterPlugin(plugins[i]);
- }
-
- if (options.enableColumnReorder) {
- $headers.filter(":ui-sortable").sortable("destroy");
- }
-
- unbindAncestorScrollEvents();
- $container.unbind(".slickgrid");
- removeCssRules();
-
- $canvas.unbind("draginit dragstart dragend drag");
- $container.empty().removeClass(uid);
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // General
-
- function trigger(evt, args, e) {
- e = e || new Slick.EventData();
- args = args || {};
- args.grid = self;
- return evt.notify(args, e, self);
- }
-
- function getEditorLock() {
- return options.editorLock;
- }
-
- function getEditController() {
- return editController;
- }
-
- function getColumnIndex(id) {
- return columnsById[id];
- }
-
- function autosizeColumns() {
- var i, c,
- widths = [],
- shrinkLeeway = 0,
- total = 0,
- prevTotal,
- availWidth = viewportHasVScroll ? viewportW - scrollbarDimensions.width : viewportW;
-
- for (i = 0; i < columns.length; i++) {
- c = columns[i];
- widths.push(c.width);
- total += c.width;
- if (c.resizable) {
- shrinkLeeway += c.width - Math.max(c.minWidth, absoluteColumnMinWidth);
- }
- }
-
- // shrink
- prevTotal = total;
- while (total > availWidth && shrinkLeeway) {
- var shrinkProportion = (total - availWidth) / shrinkLeeway;
- for (i = 0; i < columns.length && total > availWidth; i++) {
- c = columns[i];
- var width = widths[i];
- if (!c.resizable || width <= c.minWidth || width <= absoluteColumnMinWidth) {
- continue;
- }
- var absMinWidth = Math.max(c.minWidth, absoluteColumnMinWidth);
- var shrinkSize = Math.floor(shrinkProportion * (width - absMinWidth)) || 1;
- shrinkSize = Math.min(shrinkSize, width - absMinWidth);
- total -= shrinkSize;
- shrinkLeeway -= shrinkSize;
- widths[i] -= shrinkSize;
- }
- if (prevTotal <= total) { // avoid infinite loop
- break;
- }
- prevTotal = total;
- }
-
- // grow
- prevTotal = total;
- while (total < availWidth) {
- var growProportion = availWidth / total;
- for (i = 0; i < columns.length && total < availWidth; i++) {
- c = columns[i];
- var currentWidth = widths[i];
- var growSize;
-
- if (!c.resizable || c.maxWidth <= currentWidth) {
- growSize = 0;
- } else {
- growSize = Math.min(Math.floor(growProportion * currentWidth) - currentWidth, (c.maxWidth - currentWidth) || 1000000) || 1;
- }
- total += growSize;
- widths[i] += (total <= availWidth ? growSize : 0);
- }
- if (prevTotal >= total) { // avoid infinite loop
- break;
- }
- prevTotal = total;
- }
-
- var reRender = false;
- for (i = 0; i < columns.length; i++) {
- if (columns[i].rerenderOnResize && columns[i].width != widths[i]) {
- reRender = true;
- }
- columns[i].width = widths[i];
- }
-
- applyColumnHeaderWidths();
- updateCanvasWidth(true);
- if (reRender) {
- invalidateAllRows();
- render();
- }
- }
-
- function applyColumnHeaderWidths() {
- if (!initialized) { return; }
- var h;
- for (var i = 0, headers = $headers.children(), ii = headers.length; i < ii; i++) {
- h = $(headers[i]);
- if (jQueryNewWidthBehaviour) {
- if (h.outerWidth() !== columns[i].width) {
- h.outerWidth(columns[i].width);
- }
- } else {
- if (h.width() !== columns[i].width - headerColumnWidthDiff) {
- h.width(columns[i].width - headerColumnWidthDiff);
- }
- }
- }
-
- updateColumnCaches();
- }
-
- function applyColumnWidths() {
- var x = 0, w, rule;
- for (var i = 0; i < columns.length; i++) {
- w = columns[i].width;
-
- rule = getColumnCssRules(i);
- rule.left.style.left = x + "px";
- rule.right.style.right = (canvasWidth - x - w) + "px";
-
- x += columns[i].width;
- }
- }
-
- function setSortColumn(columnId, ascending) {
- setSortColumns([{ columnId: columnId, sortAsc: ascending}]);
- }
-
- function setSortColumns(cols) {
- sortColumns = cols;
-
- var headerColumnEls = $headers.children();
- headerColumnEls
- .removeClass("slick-header-column-sorted")
- .find(".slick-sort-indicator")
- .removeClass("slick-sort-indicator-asc slick-sort-indicator-desc");
-
- $.each(sortColumns, function(i, col) {
- if (col.sortAsc == null) {
- col.sortAsc = true;
- }
- var columnIndex = getColumnIndex(col.columnId);
- if (columnIndex != null) {
- headerColumnEls.eq(columnIndex)
- .addClass("slick-header-column-sorted")
- .find(".slick-sort-indicator")
- .addClass(col.sortAsc ? "slick-sort-indicator-asc" : "slick-sort-indicator-desc");
- }
- });
- }
-
- function getSortColumns() {
- return sortColumns;
- }
-
- function handleSelectedRangesChanged(e, ranges) {
- selectedRows = [];
- var hash = {};
- for (var i = 0; i < ranges.length; i++) {
- for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
- if (!hash[j]) { // prevent duplicates
- selectedRows.push(j);
- hash[j] = {};
- }
- for (var k = ranges[i].fromCell; k <= ranges[i].toCell; k++) {
- if (canCellBeSelected(j, k)) {
- hash[j][columns[k].id] = options.selectedCellCssClass;
- }
- }
- }
- }
-
- setCellCssStyles(options.selectedCellCssClass, hash);
-
- trigger(self.onSelectedRowsChanged, {rows: getSelectedRows(), grid: self}, e);
- }
-
- function getColumns() {
- return columns;
- }
-
- function updateColumnCaches() {
- // Pre-calculate cell boundaries.
- columnPosLeft = [];
- columnPosRight = [];
- var x = 0;
- for (var i = 0, ii = columns.length; i < ii; i++) {
- columnPosLeft[i] = x;
- columnPosRight[i] = x + columns[i].width;
- x += columns[i].width;
- }
- }
-
- function setColumns(columnDefinitions) {
- columns = columnDefinitions;
-
- columnsById = {};
- for (var i = 0; i < columns.length; i++) {
- var m = columns[i] = $.extend({}, columnDefaults, columns[i]);
- columnsById[m.id] = i;
- if (m.minWidth && m.width < m.minWidth) {
- m.width = m.minWidth;
- }
- if (m.maxWidth && m.width > m.maxWidth) {
- m.width = m.maxWidth;
- }
- }
-
- updateColumnCaches();
-
- if (initialized) {
- invalidateAllRows();
- createColumnHeaders();
- removeCssRules();
- createCssRules();
- resizeCanvas();
- applyColumnWidths();
- handleScroll();
- }
- }
-
- function getOptions() {
- return options;
- }
-
- function setOptions(args) {
- if (!getEditorLock().commitCurrentEdit()) {
- return;
- }
-
- makeActiveCellNormal();
-
- if (options.enableAddRow !== args.enableAddRow) {
- invalidateRow(getDataLength());
- }
-
- options = $.extend(options, args);
- validateAndEnforceOptions();
-
- $viewport.css("overflow-y", options.autoHeight ? "hidden" : "auto");
- render();
- }
-
- function validateAndEnforceOptions() {
- if (options.autoHeight) {
- options.leaveSpaceForNewRows = false;
- }
- }
-
- function setData(newData, scrollToTop) {
- data = newData;
- invalidateAllRows();
- updateRowCount();
- if (scrollToTop) {
- scrollTo(0);
- }
- }
-
- function getData() {
- return data;
- }
-
- function getDataLength() {
- if (data.getLength) {
- return data.getLength();
- } else {
- return data.length;
- }
- }
-
- function getDataLengthIncludingAddNew() {
- return getDataLength() + (options.enableAddRow ? 2 : 1);
- }
-
- function getDataItem(i) {
- if (data.getItem) {
- return data.getItem(i);
- } else {
- return data[i];
- }
- }
-
- function getTopPanel() {
- return $topPanel[0];
- }
-
- function setTopPanelVisibility(visible) {
- if (options.showTopPanel != visible) {
- options.showTopPanel = visible;
- if (visible) {
- $topPanelScroller.slideDown("fast", resizeCanvas);
- } else {
- $topPanelScroller.slideUp("fast", resizeCanvas);
- }
- }
- }
-
- function setHeaderRowVisibility(visible) {
- if (options.showHeaderRow != visible) {
- options.showHeaderRow = visible;
- if (visible) {
- $headerRowScroller.slideDown("fast", resizeCanvas);
- } else {
- $headerRowScroller.slideUp("fast", resizeCanvas);
- }
- }
- }
-
- function getContainerNode() {
- return $container.get(0);
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Rendering / Scrolling
-
- function getRowTop(row) {
- return options.rowHeight * row - offset;
- }
-
- function getRowFromPosition(y) {
- return Math.floor((y + offset) / options.rowHeight);
- }
-
- function scrollTo(y) {
- y = Math.max(y, 0);
- y = Math.min(y, th - viewportH + (viewportHasHScroll ? scrollbarDimensions.height : 0));
-
- var oldOffset = offset;
-
- page = Math.min(n - 1, Math.floor(y / ph));
- offset = Math.round(page * cj);
- var newScrollTop = y - offset;
-
- if (offset != oldOffset) {
- var range = getVisibleRange(newScrollTop);
- cleanupRows(range);
- updateRowPositions();
- }
-
- if (prevScrollTop != newScrollTop) {
- vScrollDir = (prevScrollTop + oldOffset < newScrollTop + offset) ? 1 : -1;
- $viewport[0].scrollTop = (lastRenderedScrollTop = scrollTop = prevScrollTop = newScrollTop);
-
- trigger(self.onViewportChanged, {grid: self});
- }
- }
-
- function defaultFormatter(row, cell, value, columnDef, dataContext) {
- if (value == null) {
- return "";
- } else {
- return (value + "").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
- }
- }
-
- function getFormatter(row, column) {
- var rowMetadata = data.getItemMetadata && data.getItemMetadata(row);
-
- // look up by id, then index
- var columnOverrides = rowMetadata &&
- rowMetadata.columns &&
- (rowMetadata.columns[column.id] || rowMetadata.columns[getColumnIndex(column.id)]);
-
- return (columnOverrides && columnOverrides.formatter) ||
- (rowMetadata && rowMetadata.formatter) ||
- column.formatter ||
- (options.formatterFactory && options.formatterFactory.getFormatter(column)) ||
- options.defaultFormatter;
- }
-
- function getEditor(row, cell) {
- var column = columns[cell];
- var rowMetadata = data.getItemMetadata && data.getItemMetadata(row);
- var columnMetadata = rowMetadata && rowMetadata.columns;
-
- if (columnMetadata && columnMetadata[column.id] && columnMetadata[column.id].editor !== undefined) {
- return columnMetadata[column.id].editor;
- }
- if (columnMetadata && columnMetadata[cell] && columnMetadata[cell].editor !== undefined) {
- return columnMetadata[cell].editor;
- }
-
- return column.editor || (options.editorFactory && options.editorFactory.getEditor(column));
- }
-
- function getDataItemValueForColumn(item, columnDef) {
- if (options.dataItemColumnValueExtractor) {
- return options.dataItemColumnValueExtractor(item, columnDef);
- }
- return item[columnDef.field];
- }
-
- function appendRowHtml(stringArray, row, range, dataLength) {
- var d = getDataItem(row);
- var dataLoading = row < dataLength && !d;
- var diff = dataLength - row;
- var rowCss = "sr" +
- (dataLoading ? " loading" : "") +
- (row === activeRow ? " active" : "") +
- (((options.enableAddRow && diff < 0) || diff == 0) ? "" : (row % 2 == 1 ? " odd" : " even"));
-
- if (!d && options.enableAddRow && diff == 0) {
- rowCss += " " + options.addNewRowCssClass;
- }
-
- var metadata = data.getItemMetadata && data.getItemMetadata(row);
-
- if (metadata && metadata.cssClasses) {
- rowCss += " " + metadata.cssClasses;
- }
-
- stringArray.push("<div class='ui-widget-content " + rowCss + "' style='top:" + getRowTop(row) + "px'>");
-
- if (options.enableAddRow ? diff < 0 : diff == 0) {
- stringArray.push("</div>");
- return;
- }
-
- var colspan, m;
- for (var i = 0, ii = columns.length; i < ii; i++) {
- m = columns[i];
- colspan = 1;
- if (metadata && metadata.columns) {
- var columnData = metadata.columns[m.id] || metadata.columns[i];
- colspan = (columnData && columnData.colspan) || 1;
- if (colspan === "*") {
- colspan = ii - i;
- }
- }
-
- // Do not render cells outside of the viewport.
- if (columnPosRight[Math.min(ii - 1, i + colspan - 1)] > range.leftPx) {
- if (columnPosLeft[i] > range.rightPx) {
- // All columns to the right are outside the range.
- break;
- }
-
- appendCellHtml(stringArray, row, i, colspan, d);
- }
-
- if (colspan > 1) {
- i += (colspan - 1);
- }
- }
-
- stringArray.push("</div>");
- }
-
- function appendCellHtml(stringArray, row, cell, colspan, item) {
- // stringArray: stringBuilder containing the HTML parts
- // row, cell: row and column index
- // colspan: HTML colspan
- // item: grid data for row
-
- var m = columns[cell];
- var cellCss = "sc l" + cell + " r" + Math.min(columns.length - 1, cell + colspan - 1) +
- (m.cssClass ? " " + m.cssClass : "");
- if (row === activeRow && cell === activeCell) {
- cellCss += (" active");
- }
-
- if (!item) {
- var diff = getDataLength() - row;
- if (options.enableAddRow ? diff < 0 : diff == 0)
- return;
- }
-
- // TODO: merge them together in the setter
- for (var key in cellCssClasses) {
- if (cellCssClasses[key][row] && cellCssClasses[key][row][m.id]) {
- cellCss += (" " + cellCssClasses[key][row][m.id]);
- }
- }
-
- stringArray.push("<div class='" + cellCss + "'>");
-
- // if there is a corresponding row (if not, this is the Add New row or this data hasn't been loaded yet)
- if (item) {
- var value = getDataItemValueForColumn(item, m);
- stringArray.push(getFormatter(row, m)(row, cell, value, m, item));
- }
-
- stringArray.push("</div>");
-
- rowsCache[row].cellRenderQueue.push(cell);
- rowsCache[row].cellColSpans[cell] = colspan;
- }
-
-
- function cleanupRows(rangeToKeep) {
- for (var i in rowsCache) {
- if (((i = parseInt(i, 10)) !== activeRow) && (i < rangeToKeep.top || i > rangeToKeep.bottom)) {
- removeRowFromCache(i);
- }
- }
- if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
- }
-
- function invalidate() {
- updateRowCount();
- invalidateAllRows();
- render();
- }
-
- function invalidateAllRows() {
- if (currentEditor) {
- makeActiveCellNormal();
- }
- for (var row in rowsCache) {
- removeRowFromCache(row);
- }
- if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
- }
-
- function queuePostProcessedRowForCleanup(cacheEntry, postProcessedRow, rowIdx) {
- postProcessgroupId++;
-
- // store and detach node for later async cleanup
- for (var columnIdx in postProcessedRow) {
- if (postProcessedRow.hasOwnProperty(columnIdx)) {
- postProcessedCleanupQueue.push({
- actionType: 'C',
- groupId: postProcessgroupId,
- node: cacheEntry.cellNodesByColumnIdx[ columnIdx | 0],
- columnIdx: columnIdx | 0,
- rowIdx: rowIdx
- });
- }
- }
- postProcessedCleanupQueue.push({
- actionType: 'R',
- groupId: postProcessgroupId,
- node: cacheEntry.rowNode
- });
- $(cacheEntry.rowNode).detach();
- }
-
- function queuePostProcessedCellForCleanup(cellnode, columnIdx, rowIdx) {
- postProcessedCleanupQueue.push({
- actionType: 'C',
- groupId: postProcessgroupId,
- node: cellnode,
- columnIdx: columnIdx,
- rowIdx: rowIdx
- });
- $(cellnode).detach();
- }
-
- function removeRowFromCache(row) {
- var cacheEntry = rowsCache[row];
- if (!cacheEntry) {
- return;
- }
-
- if (rowNodeFromLastMouseWheelEvent === cacheEntry.rowNode) {
- cacheEntry.rowNode.style.display = 'none';
- zombieRowNodeFromLastMouseWheelEvent = rowNodeFromLastMouseWheelEvent;
- zombieRowCacheFromLastMouseWheelEvent = cacheEntry;
- zombieRowPostProcessedFromLastMouseWheelEvent = postProcessedRows[row];
- // ignore post processing cleanup in this case - it will be dealt with later
- } else {
- if (options.enableAsyncPostRenderCleanup && postProcessedRows[row]) {
- queuePostProcessedRowForCleanup(cacheEntry, postProcessedRows[row], row);
- } else {
- $canvas[0].removeChild(cacheEntry.rowNode);
- }
- }
-
- delete rowsCache[row];
- delete postProcessedRows[row];
- renderedRows--;
- counter_rows_removed++;
- }
-
- function invalidateRows(rows) {
- var i, rl;
- if (!rows || !rows.length) {
- return;
- }
- vScrollDir = 0;
- for (i = 0, rl = rows.length; i < rl; i++) {
- if (currentEditor && activeRow === rows[i]) {
- makeActiveCellNormal();
- }
- if (rowsCache[rows[i]]) {
- removeRowFromCache(rows[i]);
- }
- }
- if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
-
- }
-
- function invalidateRow(row) {
- invalidateRows([row]);
- }
-
- function updateCell(row, cell) {
- var cellNode = getCellNode(row, cell);
- if (!cellNode) {
- return;
- }
-
- var m = columns[cell], d = getDataItem(row);
- if (currentEditor && activeRow === row && activeCell === cell) {
- currentEditor.loadValue(d);
- } else {
- cellNode.innerHTML = d ? getFormatter(row, m)(row, cell, getDataItemValueForColumn(d, m), m, d) : "";
- invalidatePostProcessingResults(row);
- }
- }
-
- function updateRow(row) {
- var cacheEntry = rowsCache[row];
- if (!cacheEntry) {
- return;
- }
-
- ensureCellNodesInRowsCache(row);
-
- var d = getDataItem(row);
-
- for (var columnIdx in cacheEntry.cellNodesByColumnIdx) {
- if (!cacheEntry.cellNodesByColumnIdx.hasOwnProperty(columnIdx)) {
- continue;
- }
-
- columnIdx = columnIdx | 0;
- var m = columns[columnIdx],
- node = cacheEntry.cellNodesByColumnIdx[columnIdx];
-
- if (row === activeRow && columnIdx === activeCell && currentEditor) {
- currentEditor.loadValue(d);
- } else if (d) {
- node.innerHTML = getFormatter(row, m)(row, columnIdx, getDataItemValueForColumn(d, m), m, d);
- } else {
- node.innerHTML = "";
- }
- }
-
- invalidatePostProcessingResults(row);
- }
-
- function getViewportHeight() {
- return parseFloat($.css($container[0], "height", true)) -
- parseFloat($.css($container[0], "paddingTop", true)) -
- parseFloat($.css($container[0], "paddingBottom", true)) -
- parseFloat($.css($headerScroller[0], "height")) - getVBoxDelta($headerScroller) -
- (options.showTopPanel ? options.topPanelHeight + getVBoxDelta($topPanelScroller) : 0) -
- (options.showHeaderRow ? options.headerRowHeight + getVBoxDelta($headerRowScroller) : 0);
- }
-
- function resizeCanvas() {
- if (!initialized) { return; }
- if (options.autoHeight) {
- viewportH = options.rowHeight * getDataLengthIncludingAddNew();
- } else {
- viewportH = getViewportHeight();
- }
-
- numVisibleRows = Math.ceil(viewportH / options.rowHeight);
- viewportW = parseFloat($.css($container[0], "width", true));
- if (!options.autoHeight) {
- $viewport.height(viewportH);
- }
-
- if (options.forceFitColumns) {
- autosizeColumns();
- }
-
- updateRowCount();
- handleScroll();
- // Since the width has changed, force the render() to reevaluate virtually rendered cells.
- lastRenderedScrollLeft = -1;
- render();
- }
-
- function updateRowCount() {
- if (!initialized) { return; }
-
- var dataLengthIncludingAddNew = getDataLengthIncludingAddNew();
- var numberOfRows = dataLengthIncludingAddNew +
- (options.leaveSpaceForNewRows ? numVisibleRows - 1 : 0);
-
- var oldViewportHasVScroll = viewportHasVScroll;
- // with autoHeight, we do not need to accommodate the vertical scroll bar
- viewportHasVScroll = !options.autoHeight && (numberOfRows * options.rowHeight > viewportH);
-
- makeActiveCellNormal();
-
- // remove the rows that are now outside of the data range
- // this helps avoid redundant calls to .removeRow() when the size of the data decreased by thousands of rows
- var l = dataLengthIncludingAddNew - 1;
- for (var i in rowsCache) {
- if (i >= l) {
- removeRowFromCache(i);
- }
- }
- if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
-
- if (activeCellNode && activeRow > l) {
- resetActiveCell();
- }
-
- var oldH = h;
- th = Math.max(options.rowHeight * numberOfRows, viewportH - scrollbarDimensions.height);
- if (th < maxSupportedCssHeight) {
- // just one page
- h = ph = th;
- n = 1;
- cj = 0;
- } else {
- // break into pages
- h = maxSupportedCssHeight;
- ph = h / 100;
- n = Math.floor(th / ph);
- cj = (th - h) / (n - 1);
- }
-
- if (h !== oldH) {
- $canvas.css("height", h);
- scrollTop = $viewport[0].scrollTop;
- }
-
- var oldScrollTopInRange = (scrollTop + offset <= th - viewportH);
-
- if (th == 0 || scrollTop == 0) {
- page = offset = 0;
- } else if (oldScrollTopInRange) {
- // maintain virtual position
- scrollTo(scrollTop + offset);
- } else {
- // scroll to bottom
- scrollTo(th - viewportH);
- }
-
- if (h != oldH && options.autoHeight) {
- resizeCanvas();
- }
-
- if (options.forceFitColumns && oldViewportHasVScroll != viewportHasVScroll) {
- autosizeColumns();
- }
- updateCanvasWidth(false);
- }
-
- function getVisibleRange(viewportTop, viewportLeft) {
- if (viewportTop == null) {
- viewportTop = scrollTop;
- }
- if (viewportLeft == null) {
- viewportLeft = scrollLeft;
- }
-
- return {
- top: getRowFromPosition(viewportTop),
- bottom: getRowFromPosition(viewportTop + viewportH) + 1,
- leftPx: viewportLeft,
- rightPx: viewportLeft + viewportW
- };
- }
-
- function getRenderedRange(viewportTop, viewportLeft) {
- var range = getVisibleRange(viewportTop, viewportLeft);
- var buffer = Math.round(viewportH / options.rowHeight);
- var minBuffer = 3;
-
- if (vScrollDir == -1) {
- range.top -= buffer;
- range.bottom += minBuffer;
- } else if (vScrollDir == 1) {
- range.top -= minBuffer;
- range.bottom += buffer;
- } else {
- range.top -= minBuffer;
- range.bottom += minBuffer;
- }
-
- range.top = Math.max(0, range.top);
- range.bottom = Math.min(getDataLengthIncludingAddNew() - 1, range.bottom);
-
- range.leftPx -= viewportW;
- range.rightPx += viewportW;
-
- range.leftPx = Math.max(0, range.leftPx);
- range.rightPx = Math.min(canvasWidth, range.rightPx);
-
- return range;
- }
-
- function ensureCellNodesInRowsCache(row) {
- var cacheEntry = rowsCache[row];
- if (cacheEntry) {
- if (cacheEntry.cellRenderQueue.length) {
- var lastChild = cacheEntry.rowNode.lastChild;
- while (cacheEntry.cellRenderQueue.length) {
- var columnIdx = cacheEntry.cellRenderQueue.pop();
- cacheEntry.cellNodesByColumnIdx[columnIdx] = lastChild;
- lastChild = lastChild.previousSibling;
- }
- }
- }
- }
-
- function cleanUpCells(range, row) {
- var totalCellsRemoved = 0;
- var cacheEntry = rowsCache[row];
-
- // Remove cells outside the range.
- var cellsToRemove = [];
- for (var i in cacheEntry.cellNodesByColumnIdx) {
- // I really hate it when people mess with Array.prototype.
- if (!cacheEntry.cellNodesByColumnIdx.hasOwnProperty(i)) {
- continue;
- }
-
- // This is a string, so it needs to be cast back to a number.
- i = i | 0;
-
- var colspan = cacheEntry.cellColSpans[i];
- if (columnPosLeft[i] > range.rightPx ||
- columnPosRight[Math.min(columns.length - 1, i + colspan - 1)] < range.leftPx) {
- if (!(row == activeRow && i == activeCell)) {
- cellsToRemove.push(i);
- }
- }
- }
-
- var cellToRemove, node;
- postProcessgroupId++;
- while ((cellToRemove = cellsToRemove.pop()) != null) {
- node = cacheEntry.cellNodesByColumnIdx[cellToRemove];
- if (options.enableAsyncPostRenderCleanup && postProcessedRows[row] && postProcessedRows[row][cellToRemove]) {
- queuePostProcessedCellForCleanup(node, cellToRemove, row);
- } else {
- cacheEntry.rowNode.removeChild(node);
- }
-
- delete cacheEntry.cellColSpans[cellToRemove];
- delete cacheEntry.cellNodesByColumnIdx[cellToRemove];
- if (postProcessedRows[row]) {
- delete postProcessedRows[row][cellToRemove];
- }
- totalCellsRemoved++;
- }
- }
-
- function cleanUpAndRenderCells(range) {
- var cacheEntry;
- var stringArray = [];
- var processedRows = [];
- var cellsAdded;
- var totalCellsAdded = 0;
- var colspan;
-
- for (var row = range.top, btm = range.bottom; row <= btm; row++) {
- cacheEntry = rowsCache[row];
- if (!cacheEntry) {
- continue;
- }
-
- // cellRenderQueue populated in renderRows() needs to be cleared first
- ensureCellNodesInRowsCache(row);
-
- cleanUpCells(range, row);
-
- // Render missing cells.
- cellsAdded = 0;
-
- var metadata = data.getItemMetadata && data.getItemMetadata(row);
- metadata = metadata && metadata.columns;
-
- var d = getDataItem(row);
-
- // TODO: shorten this loop (index? heuristics? binary search?)
- for (var i = 0, ii = columns.length; i < ii; i++) {
- // Cells to the right are outside the range.
- if (columnPosLeft[i] > range.rightPx) {
- break;
- }
-
- // Already rendered.
- if ((colspan = cacheEntry.cellColSpans[i]) != null) {
- i += (colspan > 1 ? colspan - 1 : 0);
- continue;
- }
-
- colspan = 1;
- if (metadata) {
- var columnData = metadata[columns[i].id] || metadata[i];
- colspan = (columnData && columnData.colspan) || 1;
- if (colspan === "*") {
- colspan = ii - i;
- }
- }
-
- if (columnPosRight[Math.min(ii - 1, i + colspan - 1)] > range.leftPx) {
- appendCellHtml(stringArray, row, i, colspan, d);
- cellsAdded++;
- }
-
- i += (colspan > 1 ? colspan - 1 : 0);
- }
-
- if (cellsAdded) {
- totalCellsAdded += cellsAdded;
- processedRows.push(row);
- }
- }
-
- if (!stringArray.length) {
- return;
- }
-
- var x = document.createElement("div");
- x.innerHTML = stringArray.join("");
-
- var processedRow;
- var node;
- while ((processedRow = processedRows.pop()) != null) {
- cacheEntry = rowsCache[processedRow];
- var columnIdx;
- while ((columnIdx = cacheEntry.cellRenderQueue.pop()) != null) {
- node = x.lastChild;
- cacheEntry.rowNode.appendChild(node);
- cacheEntry.cellNodesByColumnIdx[columnIdx] = node;
- }
- }
- }
-
- function renderRows(range) {
- var parentNode = $canvas[0],
- stringArray = [],
- rows = [],
- needToReselectCell = false,
- dataLength = getDataLength();
-
- for (var i = range.top, ii = range.bottom; i <= ii; i++) {
- if (rowsCache[i]) {
- continue;
- }
- renderedRows++;
- rows.push(i);
-
- // Create an entry right away so that appendRowHtml() can
- // start populatating it.
- rowsCache[i] = {
- "rowNode": null,
-
- // ColSpans of rendered cells (by column idx).
- // Can also be used for checking whether a cell has been rendered.
- "cellColSpans": [],
-
- // Cell nodes (by column idx). Lazy-populated by ensureCellNodesInRowsCache().
- "cellNodesByColumnIdx": [],
-
- // Column indices of cell nodes that have been rendered, but not yet indexed in
- // cellNodesByColumnIdx. These are in the same order as cell nodes added at the
- // end of the row.
- "cellRenderQueue": []
- };
-
- appendRowHtml(stringArray, i, range, dataLength);
- if (activeCellNode && activeRow === i) {
- needToReselectCell = true;
- }
- counter_rows_rendered++;
- }
-
- if (!rows.length) { return; }
-
- var x = document.createElement("div");
- x.innerHTML = stringArray.join("");
-
- for (var i = 0, ii = rows.length; i < ii; i++) {
- rowsCache[rows[i]].rowNode = parentNode.appendChild(x.firstChild);
- }
-
- if (needToReselectCell) {
- activeCellNode = getCellNode(activeRow, activeCell);
- }
- }
-
- function startPostProcessing() {
- if (!options.enableAsyncPostRender) {
- return;
- }
- clearTimeout(h_postrender);
- h_postrender = setTimeout(asyncPostProcessRows, options.asyncPostRenderDelay);
- }
-
- function startPostProcessingCleanup() {
- if (!options.enableAsyncPostRenderCleanup) {
- return;
- }
- clearTimeout(h_postrenderCleanup);
- h_postrenderCleanup = setTimeout(asyncPostProcessCleanupRows, options.asyncPostRenderCleanupDelay);
- }
-
- function invalidatePostProcessingResults(row) {
- // change status of columns to be re-rendered
- for (var columnIdx in postProcessedRows[row]) {
- if (postProcessedRows[row].hasOwnProperty(columnIdx)) {
- postProcessedRows[row][columnIdx] = 'C';
- }
- }
- postProcessFromRow = Math.min(postProcessFromRow, row);
- postProcessToRow = Math.max(postProcessToRow, row);
- startPostProcessing();
- }
-
- function updateRowPositions() {
- for (var row in rowsCache) {
- rowsCache[row].rowNode.style.top = getRowTop(row) + "px";
- }
- }
-
- function render() {
- if (!initialized) { return; }
- var visible = getVisibleRange();
- var rendered = getRenderedRange();
-
- // remove rows no longer in the viewport
- cleanupRows(rendered);
-
- // add new rows & missing cells in existing rows
- if (lastRenderedScrollLeft != scrollLeft) {
- cleanUpAndRenderCells(rendered);
- }
-
- // render missing rows
- renderRows(rendered);
-
- postProcessFromRow = visible.top;
- postProcessToRow = Math.min(getDataLengthIncludingAddNew() - 1, visible.bottom);
- startPostProcessing();
-
- lastRenderedScrollTop = scrollTop;
- lastRenderedScrollLeft = scrollLeft;
- h_render = null;
- }
-
- function handleHeaderRowScroll() {
- var scrollLeft = $headerRowScroller[0].scrollLeft;
- if (scrollLeft != $viewport[0].scrollLeft) {
- $viewport[0].scrollLeft = scrollLeft;
- }
- }
-
- function handleScroll() {
- scrollTop = $viewport[0].scrollTop;
- scrollLeft = $viewport[0].scrollLeft;
- var vScrollDist = Math.abs(scrollTop - prevScrollTop);
- var hScrollDist = Math.abs(scrollLeft - prevScrollLeft);
-
- if (hScrollDist) {
- prevScrollLeft = scrollLeft;
- $headerScroller[0].scrollLeft = scrollLeft;
- $topPanelScroller[0].scrollLeft = scrollLeft;
- $headerRowScroller[0].scrollLeft = scrollLeft;
- }
-
- if (vScrollDist) {
- vScrollDir = prevScrollTop < scrollTop ? 1 : -1;
- prevScrollTop = scrollTop;
-
- // switch virtual pages if needed
- if (vScrollDist < viewportH) {
- scrollTo(scrollTop + offset);
- } else {
- var oldOffset = offset;
- if (h == viewportH) {
- page = 0;
- } else {
- page = Math.min(n - 1, Math.floor(scrollTop * ((th - viewportH) / (h - viewportH)) * (1 / ph)));
- }
- offset = Math.round(page * cj);
- if (oldOffset != offset) {
- invalidateAllRows();
- }
- }
- }
-
- if (hScrollDist || vScrollDist) {
- if (h_render) {
- clearTimeout(h_render);
- }
-
- if (Math.abs(lastRenderedScrollTop - scrollTop) > 20 ||
- Math.abs(lastRenderedScrollLeft - scrollLeft) > 20) {
- if (options.forceSyncScrolling || (
- Math.abs(lastRenderedScrollTop - scrollTop) < viewportH &&
- Math.abs(lastRenderedScrollLeft - scrollLeft) < viewportW)) {
- render();
- } else {
- h_render = setTimeout(render, 50);
- }
-
- trigger(self.onViewportChanged, {grid: self});
- }
- }
-
- trigger(self.onScroll, {scrollLeft: scrollLeft, scrollTop: scrollTop, grid: self});
- }
-
- function asyncPostProcessRows() {
- var dataLength = getDataLength();
- while (postProcessFromRow <= postProcessToRow) {
- var row = (vScrollDir >= 0) ? postProcessFromRow++ : postProcessToRow--;
- var cacheEntry = rowsCache[row];
- if (!cacheEntry || row >= dataLength) {
- continue;
- }
-
- if (!postProcessedRows[row]) {
- postProcessedRows[row] = {};
- }
-
- ensureCellNodesInRowsCache(row);
- for (var columnIdx in cacheEntry.cellNodesByColumnIdx) {
- if (!cacheEntry.cellNodesByColumnIdx.hasOwnProperty(columnIdx)) {
- continue;
- }
-
- columnIdx = columnIdx | 0;
-
- var m = columns[columnIdx];
- var processedStatus = postProcessedRows[row][columnIdx]; // C=cleanup and re-render, R=rendered
- if (m.asyncPostRender && processedStatus !== 'R') {
- var node = cacheEntry.cellNodesByColumnIdx[columnIdx];
- if (node) {
- m.asyncPostRender(node, row, getDataItem(row), m, (processedStatus === 'C'));
- }
- postProcessedRows[row][columnIdx] = 'R';
- }
- }
-
- h_postrender = setTimeout(asyncPostProcessRows, options.asyncPostRenderDelay);
- return;
- }
- }
-
- function asyncPostProcessCleanupRows() {
- if (postProcessedCleanupQueue.length > 0) {
- var groupId = postProcessedCleanupQueue[0].groupId;
-
- // loop through all queue members with this groupID
- while (postProcessedCleanupQueue.length > 0 && postProcessedCleanupQueue[0].groupId == groupId) {
- var entry = postProcessedCleanupQueue.shift();
- if (entry.actionType == 'R') {
- $(entry.node).remove();
- }
- if (entry.actionType == 'C') {
- var column = columns[entry.columnIdx];
- if (column.asyncPostRenderCleanup && entry.node) {
- // cleanup must also remove element
- column.asyncPostRenderCleanup(entry.node, entry.rowIdx, column);
- }
- }
- }
-
- // call this function again after the specified delay
- h_postrenderCleanup = setTimeout(asyncPostProcessCleanupRows, options.asyncPostRenderCleanupDelay);
- }
- }
-
- function updateCellCssStylesOnRenderedRows(addedHash, removedHash) {
- var node, columnId, addedRowHash, removedRowHash;
- for (var row in rowsCache) {
- removedRowHash = removedHash && removedHash[row];
- addedRowHash = addedHash && addedHash[row];
-
- if (removedRowHash) {
- for (columnId in removedRowHash) {
- if (!addedRowHash || removedRowHash[columnId] != addedRowHash[columnId]) {
- node = getCellNode(row, getColumnIndex(columnId));
- if (node) {
- $(node).removeClass(removedRowHash[columnId]);
- }
- }
- }
- }
-
- if (addedRowHash) {
- for (columnId in addedRowHash) {
- if (!removedRowHash || removedRowHash[columnId] != addedRowHash[columnId]) {
- node = getCellNode(row, getColumnIndex(columnId));
- if (node) {
- $(node).addClass(addedRowHash[columnId]);
- }
- }
- }
- }
- }
- }
-
- function addCellCssStyles(key, hash) {
- if (cellCssClasses[key]) {
- throw "addCellCssStyles: cell CSS hash with key '" + key + "' already exists.";
- }
-
- cellCssClasses[key] = hash;
- updateCellCssStylesOnRenderedRows(hash, null);
-
- trigger(self.onCellCssStylesChanged, { "key": key, "hash": hash, "grid": self });
- }
-
- function removeCellCssStyles(key) {
- if (!cellCssClasses[key]) {
- return;
- }
-
- updateCellCssStylesOnRenderedRows(null, cellCssClasses[key]);
- delete cellCssClasses[key];
-
- trigger(self.onCellCssStylesChanged, { "key": key, "hash": null, "grid": self });
- }
-
- function setCellCssStyles(key, hash) {
- var prevHash = cellCssClasses[key];
-
- cellCssClasses[key] = hash;
- updateCellCssStylesOnRenderedRows(hash, prevHash);
-
- trigger(self.onCellCssStylesChanged, { "key": key, "hash": hash, "grid": self });
- }
-
- function getCellCssStyles(key) {
- return cellCssClasses[key];
- }
-
- function flashCell(row, cell, speed) {
- speed = speed || 100;
- if (rowsCache[row]) {
- var $cell = $(getCellNode(row, cell));
-
- function toggleCellClass(times) {
- if (!times) {
- return;
- }
- setTimeout(function () {
- $cell.queue(function () {
- $cell.toggleClass(options.cellFlashingCssClass).dequeue();
- toggleCellClass(times - 1);
- });
- },
- speed);
- }
-
- toggleCellClass(4);
- }
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Interactivity
-
- function handleMouseWheel(e) {
- var rowNode = $(e.target).closest(".sr")[0];
- if (rowNode != rowNodeFromLastMouseWheelEvent) {
- if (zombieRowNodeFromLastMouseWheelEvent && zombieRowNodeFromLastMouseWheelEvent != rowNode) {
- if (options.enableAsyncPostRenderCleanup && zombieRowPostProcessedFromLastMouseWheelEvent) {
- queuePostProcessedRowForCleanup(zombieRowCacheFromLastMouseWheelEvent,
- zombieRowPostProcessedFromLastMouseWheelEvent);
- } else {
- $canvas[0].removeChild(zombieRowNodeFromLastMouseWheelEvent);
- }
- zombieRowNodeFromLastMouseWheelEvent = null;
- zombieRowCacheFromLastMouseWheelEvent = null;
- zombieRowPostProcessedFromLastMouseWheelEvent = null;
-
- if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
- }
- rowNodeFromLastMouseWheelEvent = rowNode;
- }
- }
-
- function handleDragInit(e, dd) {
- var cell = getCellFromEvent(e);
- if (!cell || !cellExists(cell.row, cell.cell)) {
- return false;
- }
-
- var retval = trigger(self.onDragInit, dd, e);
- if (e.isImmediatePropagationStopped()) {
- return retval;
- }
-
- // if nobody claims to be handling drag'n'drop by stopping immediate propagation,
- // cancel out of it
- return false;
- }
-
- function handleDragStart(e, dd) {
- var cell = getCellFromEvent(e);
- if (!cell || !cellExists(cell.row, cell.cell)) {
- return false;
- }
-
- var retval = trigger(self.onDragStart, dd, e);
- if (e.isImmediatePropagationStopped()) {
- return retval;
- }
-
- return false;
- }
-
- function handleDrag(e, dd) {
- return trigger(self.onDrag, dd, e);
- }
-
- function handleDragEnd(e, dd) {
- trigger(self.onDragEnd, dd, e);
- }
-
- function handleKeyDown(e) {
- trigger(self.onKeyDown, {row: activeRow, cell: activeCell, grid: self}, e);
- var handled = e.isImmediatePropagationStopped();
- var keyCode = Slick.keyCode;
-
- if (!handled) {
- if (!e.shiftKey && !e.altKey && !e.ctrlKey) {
- if (e.which == keyCode.ESCAPE) {
- if (!getEditorLock().isActive()) {
- return; // no editing mode to cancel, allow bubbling and default processing (exit without cancelling the event)
- }
- cancelEditAndSetFocus();
- } else if (e.which == keyCode.PAGEDOWN) {
- navigatePageDown();
- handled = true;
- } else if (e.which == keyCode.PAGEUP) {
- navigatePageUp();
- handled = true;
- } else if (e.which == keyCode.LEFT) {
- handled = navigateLeft();
- } else if (e.which == keyCode.RIGHT) {
- handled = navigateRight();
- } else if (e.which == keyCode.UP) {
- handled = navigateUp();
- } else if (e.which == keyCode.DOWN) {
- handled = navigateDown();
- } else if (e.which == keyCode.TAB) {
- handled = navigateNext();
- } else if (e.which == keyCode.ENTER) {
- if (options.editable) {
- if (currentEditor) {
- // adding new row
- if (activeRow === getDataLength()) {
- navigateDown();
- } else {
- commitEditAndSetFocus();
- }
- } else {
- if (getEditorLock().commitCurrentEdit()) {
- makeActiveCellEditable();
- }
- }
- }
- handled = true;
- }
- } else if (e.which == keyCode.TAB && e.shiftKey && !e.ctrlKey && !e.altKey) {
- handled = navigatePrev();
- }
- }
-
- if (handled) {
- // the event has been handled so don't let parent element (bubbling/propagation) or browser (default) handle it
- e.stopPropagation();
- e.preventDefault();
- try {
- e.originalEvent.keyCode = 0; // prevent default behaviour for special keys in IE browsers (F3, F5, etc.)
- }
- // ignore exceptions - setting the original event's keycode throws access denied exception for "Ctrl"
- // (hitting control key only, nothing else), "Shift" (maybe others)
- catch (error) {
- }
- }
- }
-
- function handleClick(e) {
- if (!currentEditor) {
- // if this click resulted in some cell child node getting focus,
- // don't steal it back - keyboard events will still bubble up
- // IE9+ seems to default DIVs to tabIndex=0 instead of -1, so check for cell clicks directly.
- if (e.target != document.activeElement || $(e.target).hasClass("sc")) {
- setFocus();
- }
- }
-
- var cell = getCellFromEvent(e);
- if (!cell || (currentEditor !== null && activeRow == cell.row && activeCell == cell.cell)) {
- return;
- }
-
- trigger(self.onClick, {row: cell.row, cell: cell.cell, grid: self}, e);
- if (e.isImmediatePropagationStopped()) {
- return;
- }
-
- if ((activeCell != cell.cell || activeRow != cell.row) && canCellBeActive(cell.row, cell.cell)) {
- if (!getEditorLock().isActive() || getEditorLock().commitCurrentEdit()) {
- scrollRowIntoView(cell.row, false);
- setActiveCellInternal(getCellNode(cell.row, cell.cell));
- }
- }
- }
-
- function handleContextMenu(e) {
- var $cell = $(e.target).closest(".sc", $canvas);
- if ($cell.length === 0) {
- return;
- }
-
- // are we editing this cell?
- if (activeCellNode === $cell[0] && currentEditor !== null) {
- return;
- }
-
- trigger(self.onContextMenu, {grid: self}, e);
- }
-
- function handleDblClick(e) {
- var cell = getCellFromEvent(e);
- if (!cell || (currentEditor !== null && activeRow == cell.row && activeCell == cell.cell)) {
- return;
- }
-
- trigger(self.onDblClick, {row: cell.row, cell: cell.cell, grid: self}, e);
- if (e.isImmediatePropagationStopped()) {
- return;
- }
-
- if (options.editable) {
- gotoCell(cell.row, cell.cell, true);
- }
- }
-
- function handleHeaderMouseEnter(e) {
- trigger(self.onHeaderMouseEnter, {
- "column": $(this).data("column"),
- "grid": self
- }, e);
- }
-
- function handleHeaderMouseLeave(e) {
- trigger(self.onHeaderMouseLeave, {
- "column": $(this).data("column"),
- "grid": self
- }, e);
- }
-
- function handleHeaderContextMenu(e) {
- var $header = $(e.target).closest(".slick-header-column", ".slick-header-columns");
- var column = $header && $header.data("column");
- trigger(self.onHeaderContextMenu, {column: column, grid: self}, e);
- }
-
- function handleHeaderClick(e) {
- var $header = $(e.target).closest(".slick-header-column", ".slick-header-columns");
- var column = $header && $header.data("column");
- if (column) {
- trigger(self.onHeaderClick, {column: column, grid: self}, e);
- }
- }
-
- function handleMouseEnter(e) {
- trigger(self.onMouseEnter, {grid: self}, e);
- }
-
- function handleMouseLeave(e) {
- trigger(self.onMouseLeave, {grid: self}, e);
- }
-
- function cellExists(row, cell) {
- return !(row < 0 || row >= getDataLength() || cell < 0 || cell >= columns.length);
- }
-
- function getCellFromPoint(x, y) {
- var row = getRowFromPosition(y);
- var cell = 0;
-
- var w = 0;
- for (var i = 0; i < columns.length && w < x; i++) {
- w += columns[i].width;
- cell++;
- }
-
- if (cell < 0) {
- cell = 0;
- }
-
- return {row: row, cell: cell - 1};
- }
-
- function getCellFromNode(cellNode) {
- // read column number from .l<columnNumber> CSS class
- var cls = /l\d+/.exec(cellNode.className);
- if (!cls) {
- throw "getCellFromNode: cannot get cell - " + cellNode.className;
- }
- return parseInt(cls[0].substr(1, cls[0].length - 1), 10);
- }
-
- function getRowFromNode(rowNode) {
- for (var row in rowsCache) {
- if (rowsCache[row].rowNode === rowNode) {
- return row | 0;
- }
- }
-
- return null;
- }
-
- function getCellFromEvent(e) {
- var $cell = $(e.target).closest(".sc", $canvas);
- if (!$cell.length) {
- return null;
- }
-
- var row = getRowFromNode($cell[0].parentNode);
- var cell = getCellFromNode($cell[0]);
-
- if (row == null || cell == null) {
- return null;
- } else {
- return {
- "row": row,
- "cell": cell
- };
- }
- }
-
- function getCellNodeBox(row, cell) {
- if (!cellExists(row, cell)) {
- return null;
- }
-
- var y1 = getRowTop(row);
- var y2 = y1 + options.rowHeight - 1;
- var x1 = 0;
- for (var i = 0; i < cell; i++) {
- x1 += columns[i].width;
- }
- var x2 = x1 + columns[cell].width;
-
- return {
- top: y1,
- left: x1,
- bottom: y2,
- right: x2
- };
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Cell switching
-
- function resetActiveCell() {
- setActiveCellInternal(null, false);
- }
-
- function setFocus() {
- if (tabbingDirection == -1) {
- $focusSink[0].focus();
- } else {
- $focusSink2[0].focus();
- }
- }
-
- function scrollCellIntoView(row, cell, doPaging) {
- scrollRowIntoView(row, doPaging);
-
- var colspan = getColspan(row, cell);
- var left = columnPosLeft[cell],
- right = columnPosRight[cell + (colspan > 1 ? colspan - 1 : 0)],
- scrollRight = scrollLeft + viewportW;
-
- if (left < scrollLeft) {
- $viewport.scrollLeft(left);
- handleScroll();
- render();
- } else if (right > scrollRight) {
- $viewport.scrollLeft(Math.min(left, right - $viewport[0].clientWidth));
- handleScroll();
- render();
- }
- }
-
- function setActiveCellInternal(newCell, opt_editMode) {
- if (activeCellNode !== null) {
- makeActiveCellNormal();
- $(activeCellNode).removeClass("active");
- if (rowsCache[activeRow]) {
- $(rowsCache[activeRow].rowNode).removeClass("active");
- }
- }
-
- var activeCellChanged = (activeCellNode !== newCell);
- activeCellNode = newCell;
-
- if (activeCellNode != null) {
- activeRow = getRowFromNode(activeCellNode.parentNode);
- activeCell = activePosX = getCellFromNode(activeCellNode);
-
- if (opt_editMode == null) {
- opt_editMode = (activeRow == getDataLength()) || options.autoEdit;
- }
-
- $(activeCellNode).addClass("active");
- $(rowsCache[activeRow].rowNode).addClass("active");
-
- if (options.editable && opt_editMode && isCellPotentiallyEditable(activeRow, activeCell)) {
- clearTimeout(h_editorLoader);
-
- if (options.asyncEditorLoading) {
- h_editorLoader = setTimeout(function () {
- makeActiveCellEditable();
- }, options.asyncEditorLoadDelay);
- } else {
- makeActiveCellEditable();
- }
- }
- } else {
- activeRow = activeCell = null;
- }
-
- if (activeCellChanged) {
- trigger(self.onActiveCellChanged, getActiveCell());
- }
- }
-
- function clearTextSelection() {
- if (document.selection && document.selection.empty) {
- try {
- //IE fails here if selected element is not in dom
- document.selection.empty();
- } catch (e) { }
- } else if (window.getSelection) {
- var sel = window.getSelection();
- if (sel && sel.removeAllRanges) {
- sel.removeAllRanges();
- }
- }
- }
-
- function isCellPotentiallyEditable(row, cell) {
- var dataLength = getDataLength();
- // is the data for this row loaded?
- if (row < dataLength && !getDataItem(row)) {
- return false;
- }
-
- // are we in the Add New row? can we create new from this cell?
- if (columns[cell].cannotTriggerInsert && row >= dataLength) {
- return false;
- }
-
- // does this cell have an editor?
- if (!getEditor(row, cell)) {
- return false;
- }
-
- return true;
- }
-
- function makeActiveCellNormal() {
- if (!currentEditor) {
- return;
- }
- trigger(self.onBeforeCellEditorDestroy, {editor: currentEditor, grid: self});
- currentEditor.destroy();
- currentEditor = null;
-
- if (activeCellNode) {
- var d = getDataItem(activeRow);
- $(activeCellNode).removeClass("editable invalid");
- if (d) {
- var column = columns[activeCell];
- var formatter = getFormatter(activeRow, column);
- activeCellNode.innerHTML = formatter(activeRow, activeCell, getDataItemValueForColumn(d, column), column, d, self);
- invalidatePostProcessingResults(activeRow);
- }
- }
-
- // if there previously was text selected on a page (such as selected text in the edit cell just removed),
- // IE can't set focus to anything else correctly
- if (navigator.userAgent.toLowerCase().match(/msie/)) {
- clearTextSelection();
- }
-
- getEditorLock().deactivate(editController);
- }
-
- function makeActiveCellEditable(editor) {
- if (!activeCellNode) {
- return;
- }
- if (!options.editable) {
- throw "Grid : makeActiveCellEditable : should never get called when options.editable is false";
- }
-
- // cancel pending async call if there is one
- clearTimeout(h_editorLoader);
-
- if (!isCellPotentiallyEditable(activeRow, activeCell)) {
- return;
- }
-
- var columnDef = columns[activeCell];
- var item = getDataItem(activeRow);
-
- if (trigger(self.onBeforeEditCell, {row: activeRow, cell: activeCell, item: item, column: columnDef, grid: self}) === false) {
- setFocus();
- return;
- }
-
- getEditorLock().activate(editController);
- $(activeCellNode).addClass("editable");
-
- var useEditor = editor || getEditor(activeRow, activeCell);
-
- // don't clear the cell if a custom editor is passed through
- if (!editor && !useEditor.suppressClearOnEdit) {
- activeCellNode.innerHTML = "";
- }
-
- currentEditor = new useEditor({
- grid: self,
- gridPosition: absBox($container[0]),
- position: absBox(activeCellNode),
- container: activeCellNode,
- column: columnDef,
- item: item || {},
- commitChanges: commitEditAndSetFocus,
- cancelChanges: cancelEditAndSetFocus
- });
-
- if (item) {
- currentEditor.loadValue(item);
- }
-
- serializedEditorValue = currentEditor.serializeValue();
-
- if (currentEditor.position) {
- handleActiveCellPositionChange();
- }
- }
-
- function commitEditAndSetFocus() {
- // if the commit fails, it would do so due to a validation error
- // if so, do not steal the focus from the editor
- if (getEditorLock().commitCurrentEdit()) {
- setFocus();
- if (options.autoEdit) {
- navigateDown();
- }
- }
- }
-
- function cancelEditAndSetFocus() {
- if (getEditorLock().cancelCurrentEdit()) {
- setFocus();
- }
- }
-
- function absBox(elem) {
- var box = {
- top: elem.offsetTop,
- left: elem.offsetLeft,
- bottom: 0,
- right: 0,
- width: $(elem).outerWidth(),
- height: $(elem).outerHeight(),
- visible: true};
- box.bottom = box.top + box.height;
- box.right = box.left + box.width;
-
- // walk up the tree
- var offsetParent = elem.offsetParent;
- while ((elem = elem.parentNode) != document.body) {
- if (elem == null) break;
-
- if (box.visible && elem.scrollHeight != elem.offsetHeight && $(elem).css("overflowY") != "visible") {
- box.visible = box.bottom > elem.scrollTop && box.top < elem.scrollTop + elem.clientHeight;
- }
-
- if (box.visible && elem.scrollWidth != elem.offsetWidth && $(elem).css("overflowX") != "visible") {
- box.visible = box.right > elem.scrollLeft && box.left < elem.scrollLeft + elem.clientWidth;
- }
-
- box.left -= elem.scrollLeft;
- box.top -= elem.scrollTop;
-
- if (elem === offsetParent) {
- box.left += elem.offsetLeft;
- box.top += elem.offsetTop;
- offsetParent = elem.offsetParent;
- }
-
- box.bottom = box.top + box.height;
- box.right = box.left + box.width;
- }
-
- return box;
- }
-
- function getActiveCellPosition() {
- return absBox(activeCellNode);
- }
-
- function getGridPosition() {
- return absBox($container[0])
- }
-
- function handleActiveCellPositionChange() {
- if (!activeCellNode) {
- return;
- }
-
- trigger(self.onActiveCellPositionChanged, {grid: self});
-
- if (currentEditor) {
- var cellBox = getActiveCellPosition();
- if (currentEditor.show && currentEditor.hide) {
- if (!cellBox.visible) {
- currentEditor.hide();
- } else {
- currentEditor.show();
- }
- }
-
- if (currentEditor.position) {
- currentEditor.position(cellBox);
- }
- }
- }
-
- function getCellEditor() {
- return currentEditor;
- }
-
- function getActiveCell() {
- if (!activeCellNode) {
- return null;
- } else {
- return {row: activeRow, cell: activeCell, grid: self};
- }
- }
-
- function getActiveCellNode() {
- return activeCellNode;
- }
-
- function scrollRowIntoView(row, doPaging) {
- var rowAtTop = row * options.rowHeight;
- var rowAtBottom = (row + 1) * options.rowHeight - viewportH + (viewportHasHScroll ? scrollbarDimensions.height : 0);
-
- // need to page down?
- if ((row + 1) * options.rowHeight > scrollTop + viewportH + offset) {
- scrollTo(doPaging ? rowAtTop : rowAtBottom);
- render();
- }
- // or page up?
- else if (row * options.rowHeight < scrollTop + offset) {
- scrollTo(doPaging ? rowAtBottom : rowAtTop);
- render();
- }
- }
-
- function scrollRowToTop(row) {
- scrollTo(row * options.rowHeight);
- render();
- }
-
- function scrollPage(dir) {
- var deltaRows = dir * numVisibleRows;
- scrollTo((getRowFromPosition(scrollTop) + deltaRows) * options.rowHeight);
- render();
-
- if (options.enableCellNavigation && activeRow != null) {
- var row = activeRow + deltaRows;
- var dataLengthIncludingAddNew = getDataLengthIncludingAddNew();
- if (row >= dataLengthIncludingAddNew) {
- row = dataLengthIncludingAddNew - 1;
- }
- if (row < 0) {
- row = 0;
- }
-
- var cell = 0, prevCell = null;
- var prevActivePosX = activePosX;
- while (cell <= activePosX) {
- if (canCellBeActive(row, cell)) {
- prevCell = cell;
- }
- cell += getColspan(row, cell);
- }
-
- if (prevCell !== null) {
- setActiveCellInternal(getCellNode(row, prevCell));
- activePosX = prevActivePosX;
- } else {
- resetActiveCell();
- }
- }
- }
-
- function navigatePageDown() {
- scrollPage(1);
- }
-
- function navigatePageUp() {
- scrollPage(-1);
- }
-
- function getColspan(row, cell) {
- var metadata = data.getItemMetadata && data.getItemMetadata(row);
- if (!metadata || !metadata.columns) {
- return 1;
- }
-
- var columnData = metadata.columns[columns[cell].id] || metadata.columns[cell];
- var colspan = (columnData && columnData.colspan);
- if (colspan === "*") {
- colspan = columns.length - cell;
- } else {
- colspan = colspan || 1;
- }
-
- return colspan;
- }
-
- function findFirstFocusableCell(row) {
- var cell = 0;
- while (cell < columns.length) {
- if (canCellBeActive(row, cell)) {
- return cell;
- }
- cell += getColspan(row, cell);
- }
- return null;
- }
-
- function findLastFocusableCell(row) {
- var cell = 0;
- var lastFocusableCell = null;
- while (cell < columns.length) {
- if (canCellBeActive(row, cell)) {
- lastFocusableCell = cell;
- }
- cell += getColspan(row, cell);
- }
- return lastFocusableCell;
- }
-
- function gotoRight(row, cell, posX) {
- if (cell >= columns.length) {
- return null;
- }
-
- do {
- cell += getColspan(row, cell);
- }
- while (cell < columns.length && !canCellBeActive(row, cell));
-
- if (cell < columns.length) {
- return {
- "row": row,
- "cell": cell,
- "posX": cell
- };
- }
- return null;
- }
-
- function gotoLeft(row, cell, posX) {
- if (cell <= 0) {
- return null;
- }
-
- var firstFocusableCell = findFirstFocusableCell(row);
- if (firstFocusableCell === null || firstFocusableCell >= cell) {
- return null;
- }
-
- var prev = {
- "row": row,
- "cell": firstFocusableCell,
- "posX": firstFocusableCell
- };
- var pos;
- while (true) {
- pos = gotoRight(prev.row, prev.cell, prev.posX);
- if (!pos) {
- return null;
- }
- if (pos.cell >= cell) {
- return prev;
- }
- prev = pos;
- }
- }
-
- function gotoDown(row, cell, posX) {
- var prevCell;
- var dataLengthIncludingAddNew = getDataLengthIncludingAddNew();
- while (true) {
- if (++row >= dataLengthIncludingAddNew) {
- return null;
- }
-
- prevCell = cell = 0;
- while (cell <= posX) {
- prevCell = cell;
- cell += getColspan(row, cell);
- }
-
- if (canCellBeActive(row, prevCell)) {
- return {
- "row": row,
- "cell": prevCell,
- "posX": posX
- };
- }
- }
- }
-
- function gotoUp(row, cell, posX) {
- var prevCell;
- while (true) {
- if (--row < 0) {
- return null;
- }
-
- prevCell = cell = 0;
- while (cell <= posX) {
- prevCell = cell;
- cell += getColspan(row, cell);
- }
-
- if (canCellBeActive(row, prevCell)) {
- return {
- "row": row,
- "cell": prevCell,
- "posX": posX
- };
- }
- }
- }
-
- function gotoNext(row, cell, posX) {
- if (row == null && cell == null) {
- row = cell = posX = 0;
- if (canCellBeActive(row, cell)) {
- return {
- "row": row,
- "cell": cell,
- "posX": cell
- };
- }
- }
-
- var pos = gotoRight(row, cell, posX);
- if (pos) {
- return pos;
- }
-
- var firstFocusableCell = null;
- var dataLengthIncludingAddNew = getDataLengthIncludingAddNew();
- while (++row < dataLengthIncludingAddNew) {
- firstFocusableCell = findFirstFocusableCell(row);
- if (firstFocusableCell !== null) {
- return {
- "row": row,
- "cell": firstFocusableCell,
- "posX": firstFocusableCell
- };
- }
- }
- return null;
- }
-
- function gotoPrev(row, cell, posX) {
- if (row == null && cell == null) {
- row = getDataLengthIncludingAddNew() - 1;
- cell = posX = columns.length - 1;
- if (canCellBeActive(row, cell)) {
- return {
- "row": row,
- "cell": cell,
- "posX": cell
- };
- }
- }
-
- var pos;
- var lastSelectableCell;
- while (!pos) {
- pos = gotoLeft(row, cell, posX);
- if (pos) {
- break;
- }
- if (--row < 0) {
- return null;
- }
-
- cell = 0;
- lastSelectableCell = findLastFocusableCell(row);
- if (lastSelectableCell !== null) {
- pos = {
- "row": row,
- "cell": lastSelectableCell,
- "posX": lastSelectableCell
- };
- }
- }
- return pos;
- }
-
- function navigateRight() {
- return navigate("right");
- }
-
- function navigateLeft() {
- return navigate("left");
- }
-
- function navigateDown() {
- return navigate("down");
- }
-
- function navigateUp() {
- return navigate("up");
- }
-
- function navigateNext() {
- return navigate("next");
- }
-
- function navigatePrev() {
- return navigate("prev");
- }
-
- /**
- * @param {string} dir Navigation direction.
- * @return {boolean} Whether navigation resulted in a change of active cell.
- */
- function navigate(dir) {
- if (!options.enableCellNavigation) {
- return false;
- }
-
- if (!activeCellNode && dir != "prev" && dir != "next") {
- return false;
- }
-
- if (!getEditorLock().commitCurrentEdit()) {
- return true;
- }
- setFocus();
-
- var tabbingDirections = {
- "up": -1,
- "down": 1,
- "left": -1,
- "right": 1,
- "prev": -1,
- "next": 1
- };
- tabbingDirection = tabbingDirections[dir];
-
- var stepFunctions = {
- "up": gotoUp,
- "down": gotoDown,
- "left": gotoLeft,
- "right": gotoRight,
- "prev": gotoPrev,
- "next": gotoNext
- };
- var stepFn = stepFunctions[dir];
- var pos = stepFn(activeRow, activeCell, activePosX);
- if (pos) {
- var isAddNewRow = (pos.row == getDataLength());
- scrollCellIntoView(pos.row, pos.cell, !isAddNewRow);
- setActiveCellInternal(getCellNode(pos.row, pos.cell));
- activePosX = pos.posX;
- return true;
- } else {
- setActiveCellInternal(getCellNode(activeRow, activeCell));
- return false;
- }
- }
-
- function getCellNode(row, cell) {
- if (rowsCache[row]) {
- ensureCellNodesInRowsCache(row);
- return rowsCache[row].cellNodesByColumnIdx[cell];
- }
- return null;
- }
-
- function setActiveCell(row, cell) {
- if (!initialized) { return; }
- if (row > getDataLength() || row < 0 || cell >= columns.length || cell < 0) {
- return;
- }
-
- if (!options.enableCellNavigation) {
- return;
- }
-
- scrollCellIntoView(row, cell, false);
- setActiveCellInternal(getCellNode(row, cell), false);
- }
-
- function canCellBeActive(row, cell) {
- if (!options.enableCellNavigation || row >= getDataLengthIncludingAddNew() ||
- row < 0 || cell >= columns.length || cell < 0) {
- return false;
- }
-
- var rowMetadata = data.getItemMetadata && data.getItemMetadata(row);
- if (rowMetadata && typeof rowMetadata.focusable === "boolean") {
- return rowMetadata.focusable;
- }
-
- var columnMetadata = rowMetadata && rowMetadata.columns;
- if (columnMetadata && columnMetadata[columns[cell].id] && typeof columnMetadata[columns[cell].id].focusable === "boolean") {
- return columnMetadata[columns[cell].id].focusable;
- }
- if (columnMetadata && columnMetadata[cell] && typeof columnMetadata[cell].focusable === "boolean") {
- return columnMetadata[cell].focusable;
- }
-
- return columns[cell].focusable;
- }
-
- function canCellBeSelected(row, cell) {
- if (row >= getDataLength() || row < 0 || cell >= columns.length || cell < 0) {
- return false;
- }
-
- var rowMetadata = data.getItemMetadata && data.getItemMetadata(row);
- if (rowMetadata && typeof rowMetadata.selectable === "boolean") {
- return rowMetadata.selectable;
- }
-
- var columnMetadata = rowMetadata && rowMetadata.columns && (rowMetadata.columns[columns[cell].id] || rowMetadata.columns[cell]);
- if (columnMetadata && typeof columnMetadata.selectable === "boolean") {
- return columnMetadata.selectable;
- }
-
- return columns[cell].selectable;
- }
-
- function gotoCell(row, cell, forceEdit) {
- if (!initialized) { return; }
- if (!canCellBeActive(row, cell)) {
- return;
- }
-
- if (!getEditorLock().commitCurrentEdit()) {
- return;
- }
-
- scrollCellIntoView(row, cell, false);
-
- var newCell = getCellNode(row, cell);
-
- // if selecting the 'add new' row, start editing right away
- setActiveCellInternal(newCell, forceEdit || (row === getDataLength()) || options.autoEdit);
-
- // if no editor was created, set the focus back on the grid
- if (!currentEditor) {
- setFocus();
- }
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // IEditor implementation for the editor lock
-
- function commitCurrentEdit() {
- var item = getDataItem(activeRow);
- var column = columns[activeCell];
-
- if (currentEditor) {
- if (currentEditor.isValueChanged()) {
- var validationResults = currentEditor.validate();
-
- if (validationResults.valid) {
- if (activeRow < getDataLength()) {
- var editCommand = {
- row: activeRow,
- cell: activeCell,
- editor: currentEditor,
- serializedValue: currentEditor.serializeValue(),
- prevSerializedValue: serializedEditorValue,
- execute: function () {
- this.editor.applyValue(item, this.serializedValue);
- updateRow(this.row);
- trigger(self.onCellChange, {
- row: activeRow,
- cell: activeCell,
- item: item,
- grid: self
- });
- },
- undo: function () {
- this.editor.applyValue(item, this.prevSerializedValue);
- updateRow(this.row);
- trigger(self.onCellChange, {
- row: activeRow,
- cell: activeCell,
- item: item,
- grid: self
- });
- }
- };
-
- if (options.editCommandHandler) {
- makeActiveCellNormal();
- options.editCommandHandler(item, column, editCommand);
- } else {
- editCommand.execute();
- makeActiveCellNormal();
- }
-
- } else {
- var newItem = {};
- currentEditor.applyValue(newItem, currentEditor.serializeValue());
- makeActiveCellNormal();
- trigger(self.onAddNewRow, {item: newItem, column: column, grid: self});
- }
-
- // check whether the lock has been re-acquired by event handlers
- return !getEditorLock().isActive();
- } else {
- // Re-add the CSS class to trigger transitions, if any.
- $(activeCellNode).removeClass("invalid");
- $(activeCellNode).width(); // force layout
- $(activeCellNode).addClass("invalid");
-
- trigger(self.onValidationError, {
- editor: currentEditor,
- cellNode: activeCellNode,
- validationResults: validationResults,
- row: activeRow,
- cell: activeCell,
- column: column,
- grid: self
- });
-
- currentEditor.focus();
- return false;
- }
- }
-
- makeActiveCellNormal();
- }
- return true;
- }
-
- function cancelCurrentEdit() {
- makeActiveCellNormal();
- return true;
- }
-
- function rowsToRanges(rows) {
- var ranges = [];
- var lastCell = columns.length - 1;
- for (var i = 0; i < rows.length; i++) {
- ranges.push(new Slick.Range(rows[i], 0, rows[i], lastCell));
- }
- return ranges;
- }
-
- function getSelectedRows() {
- if (!selectionModel) {
- throw "Selection model is not set";
- }
- return selectedRows;
- }
-
- function setSelectedRows(rows) {
- if (!selectionModel) {
- throw "Selection model is not set";
- }
- selectionModel.setSelectedRanges(rowsToRanges(rows));
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Debug
-
- this.debug = function () {
- var s = "";
-
- s += ("\n" + "counter_rows_rendered: " + counter_rows_rendered);
- s += ("\n" + "counter_rows_removed: " + counter_rows_removed);
- s += ("\n" + "renderedRows: " + renderedRows);
- s += ("\n" + "numVisibleRows: " + numVisibleRows);
- s += ("\n" + "maxSupportedCssHeight: " + maxSupportedCssHeight);
- s += ("\n" + "n(umber of pages): " + n);
- s += ("\n" + "(current) page: " + page);
- s += ("\n" + "page height (ph): " + ph);
- s += ("\n" + "vScrollDir: " + vScrollDir);
-
- alert(s);
- };
-
- // a debug helper to be able to access private members
- this.eval = function (expr) {
- return eval(expr);
- };
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Public API
-
- $.extend(this, {
- "slickGridVersion": "2.2.4",
-
- // Events
- "onScroll": new Slick.Event(),
- "onSort": new Slick.Event(),
- "onHeaderMouseEnter": new Slick.Event(),
- "onHeaderMouseLeave": new Slick.Event(),
- "onHeaderContextMenu": new Slick.Event(),
- "onHeaderClick": new Slick.Event(),
- "onHeaderCellRendered": new Slick.Event(),
- "onBeforeHeaderCellDestroy": new Slick.Event(),
- "onHeaderRowCellRendered": new Slick.Event(),
- "onBeforeHeaderRowCellDestroy": new Slick.Event(),
- "onMouseEnter": new Slick.Event(),
- "onMouseLeave": new Slick.Event(),
- "onClick": new Slick.Event(),
- "onDblClick": new Slick.Event(),
- "onContextMenu": new Slick.Event(),
- "onKeyDown": new Slick.Event(),
- "onAddNewRow": new Slick.Event(),
- "onValidationError": new Slick.Event(),
- "onViewportChanged": new Slick.Event(),
- "onColumnsReordered": new Slick.Event(),
- "onColumnsResized": new Slick.Event(),
- "onCellChange": new Slick.Event(),
- "onBeforeEditCell": new Slick.Event(),
- "onBeforeCellEditorDestroy": new Slick.Event(),
- "onBeforeDestroy": new Slick.Event(),
- "onActiveCellChanged": new Slick.Event(),
- "onActiveCellPositionChanged": new Slick.Event(),
- "onDragInit": new Slick.Event(),
- "onDragStart": new Slick.Event(),
- "onDrag": new Slick.Event(),
- "onDragEnd": new Slick.Event(),
- "onSelectedRowsChanged": new Slick.Event(),
- "onCellCssStylesChanged": new Slick.Event(),
-
- // Methods
- "registerPlugin": registerPlugin,
- "unregisterPlugin": unregisterPlugin,
- "getColumns": getColumns,
- "setColumns": setColumns,
- "getColumnIndex": getColumnIndex,
- "updateColumnHeader": updateColumnHeader,
- "setSortColumn": setSortColumn,
- "setSortColumns": setSortColumns,
- "getSortColumns": getSortColumns,
- "autosizeColumns": autosizeColumns,
- "getOptions": getOptions,
- "setOptions": setOptions,
- "getData": getData,
- "getDataLength": getDataLength,
- "getDataItem": getDataItem,
- "setData": setData,
- "getSelectionModel": getSelectionModel,
- "setSelectionModel": setSelectionModel,
- "getSelectedRows": getSelectedRows,
- "setSelectedRows": setSelectedRows,
- "getContainerNode": getContainerNode,
-
- "render": render,
- "invalidate": invalidate,
- "invalidateRow": invalidateRow,
- "invalidateRows": invalidateRows,
- "invalidateAllRows": invalidateAllRows,
- "updateCell": updateCell,
- "updateRow": updateRow,
- "getViewport": getVisibleRange,
- "getRenderedRange": getRenderedRange,
- "resizeCanvas": resizeCanvas,
- "updateRowCount": updateRowCount,
- "scrollRowIntoView": scrollRowIntoView,
- "scrollRowToTop": scrollRowToTop,
- "scrollCellIntoView": scrollCellIntoView,
- "getCanvasNode": getCanvasNode,
- "focus": setFocus,
-
- "getCellFromPoint": getCellFromPoint,
- "getCellFromEvent": getCellFromEvent,
- "getActiveCell": getActiveCell,
- "setActiveCell": setActiveCell,
- "getActiveCellNode": getActiveCellNode,
- "getActiveCellPosition": getActiveCellPosition,
- "resetActiveCell": resetActiveCell,
- "editActiveCell": makeActiveCellEditable,
- "getCellEditor": getCellEditor,
- "getCellNode": getCellNode,
- "getCellNodeBox": getCellNodeBox,
- "canCellBeSelected": canCellBeSelected,
- "canCellBeActive": canCellBeActive,
- "navigatePrev": navigatePrev,
- "navigateNext": navigateNext,
- "navigateUp": navigateUp,
- "navigateDown": navigateDown,
- "navigateLeft": navigateLeft,
- "navigateRight": navigateRight,
- "navigatePageUp": navigatePageUp,
- "navigatePageDown": navigatePageDown,
- "gotoCell": gotoCell,
- "getTopPanel": getTopPanel,
- "setTopPanelVisibility": setTopPanelVisibility,
- "setHeaderRowVisibility": setHeaderRowVisibility,
- "getHeaderRow": getHeaderRow,
- "getHeaderRowColumn": getHeaderRowColumn,
- "getGridPosition": getGridPosition,
- "flashCell": flashCell,
- "addCellCssStyles": addCellCssStyles,
- "setCellCssStyles": setCellCssStyles,
- "removeCellCssStyles": removeCellCssStyles,
- "getCellCssStyles": getCellCssStyles,
-
- "init": finishInitialization,
- "destroy": destroy,
-
- // IEditor implementation
- "getEditorLock": getEditorLock,
- "getEditController": getEditController
- });
-
- init();
- }
-}(jQuery));
+/**
+ * @license
+ * (c) 2009-2016 Michael Leibman
+ * michael{dot}leibman{at}gmail{dot}com
+ * http://github.com/mleibman/slickgrid
+ *
+ * Distributed under MIT license.
+ * All rights reserved.
+ *
+ * SlickGrid v2.3
+ *
+ * NOTES:
+ * Cell/row DOM manipulations are done directly bypassing jQuery's DOM manipulation methods.
+ * This increases the speed dramatically, but can only be done safely because there are no event handlers
+ * or data associated with any cell/row DOM nodes. Cell editors must make sure they implement .destroy()
+ * and do proper cleanup.
+ */
+
+// make sure required JavaScript modules are loaded
+if (typeof jQuery === "undefined") {
+ throw new Error("SlickGrid requires jquery module to be loaded");
+}
+if (!jQuery.fn.drag) {
+ throw new Error("SlickGrid requires jquery.event.drag module to be loaded");
+}
+if (typeof Slick === "undefined") {
+ throw new Error("slick.core.js not loaded");
+}
+
+
+(function ($) {
+ // Slick.Grid
+ $.extend(true, window, {
+ Slick: {
+ Grid: SlickGrid
+ }
+ });
+
+ // shared across all grids on the page
+ var scrollbarDimensions;
+ var maxSupportedCssHeight; // browser's breaking point
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // SlickGrid class implementation (available as Slick.Grid)
+
+ /**
+ * Creates a new instance of the grid.
+ * @class SlickGrid
+ * @constructor
+ * @param {Node} container Container node to create the grid in.
+ * @param {Array,Object} data An array of objects for databinding.
+ * @param {Array} columns An array of column definitions.
+ * @param {Object} options Grid options.
+ **/
+ function SlickGrid(container, data, columns, options) {
+ // settings
+ var defaults = {
+ explicitInitialization: false,
+ rowHeight: 25,
+ defaultColumnWidth: 80,
+ enableAddRow: false,
+ leaveSpaceForNewRows: false,
+ editable: false,
+ autoEdit: true,
+ enableCellNavigation: true,
+ enableColumnReorder: true,
+ asyncEditorLoading: false,
+ asyncEditorLoadDelay: 100,
+ forceFitColumns: false,
+ enableAsyncPostRender: false,
+ asyncPostRenderDelay: 50,
+ enableAsyncPostRenderCleanup: false,
+ asyncPostRenderCleanupDelay: 40,
+ autoHeight: false,
+ editorLock: Slick.GlobalEditorLock,
+ showHeaderRow: false,
+ headerRowHeight: 25,
+ createFooterRow: false,
+ showFooterRow: false,
+ footerRowHeight: 25,
+ showTopPanel: false,
+ topPanelHeight: 25,
+ formatterFactory: null,
+ editorFactory: null,
+ cellFlashingCssClass: "flashing",
+ selectedCellCssClass: "selected",
+ multiSelect: true,
+ enableTextSelectionOnCells: false,
+ dataItemColumnValueExtractor: null,
+ fullWidthRows: false,
+ multiColumnSort: false,
+ numberedMultiColumnSort: false,
+ tristateMultiColumnSort: false,
+ defaultFormatter: defaultFormatter,
+ forceSyncScrolling: false,
+ addNewRowCssClass: "new-row",
+ preserveCopiedSelectionOnPaste: false
+ };
+
+ var columnDefaults = {
+ name: "",
+ resizable: true,
+ sortable: false,
+ minWidth: 30,
+ rerenderOnResize: false,
+ headerCssClass: null,
+ defaultSortAsc: true,
+ focusable: true,
+ selectable: true
+ };
+
+ // scroller
+ var th; // virtual height
+ var h; // real scrollable height
+ var ph; // page height
+ var n; // number of pages
+ var cj; // "jumpiness" coefficient
+
+ var page = 0; // current page
+ var offset = 0; // current page offset
+ var vScrollDir = 1;
+
+ // private
+ var initialized = false;
+ var $container;
+ var uid = "slickgrid_" + Math.round(1000000 * Math.random());
+ var self = this;
+ var $focusSink, $focusSink2;
+ var $headerScroller;
+ var $headers;
+ var $headerRow, $headerRowScroller, $headerRowSpacer;
+ var $footerRow, $footerRowScroller, $footerRowSpacer;
+ var $topPanelScroller;
+ var $topPanel;
+ var $viewport;
+ var $canvas;
+ var $style;
+ var $boundAncestors;
+ var stylesheet, columnCssRulesL, columnCssRulesR;
+ var viewportH, viewportW;
+ var canvasWidth;
+ var viewportHasHScroll, viewportHasVScroll;
+ var headerColumnWidthDiff = 0, headerColumnHeightDiff = 0, // border+padding
+ cellWidthDiff = 0, cellHeightDiff = 0, jQueryNewWidthBehaviour = false;
+ var absoluteColumnMinWidth;
+ var sortIndicatorCssClass = "slick-sort-indicator";
+
+ var tabbingDirection = 1;
+ var activePosX;
+ var activeRow, activeCell;
+ var activeCellNode = null;
+ var currentEditor = null;
+ var serializedEditorValue;
+ var editController;
+
+ var rowsCache = {};
+ var renderedRows = 0;
+ var numVisibleRows;
+ var prevScrollTop = 0;
+ var scrollTop = 0;
+ var lastRenderedScrollTop = 0;
+ var lastRenderedScrollLeft = 0;
+ var prevScrollLeft = 0;
+ var scrollLeft = 0;
+
+ var selectionModel;
+ var selectedRows = [];
+
+ var plugins = [];
+ var cellCssClasses = {};
+
+ var columnsById = {};
+ var sortColumns = [];
+ var columnPosLeft = [];
+ var columnPosRight = [];
+
+ var pagingActive = false;
+ var pagingIsLastPage = false;
+
+ // async call handles
+ var h_editorLoader = null;
+ var h_render = null;
+ var h_postrender = null;
+ var h_postrenderCleanup = null;
+ var postProcessedRows = {};
+ var postProcessToRow = null;
+ var postProcessFromRow = null;
+ var postProcessedCleanupQueue = [];
+ var postProcessgroupId = 0;
+
+ // perf counters
+ var counter_rows_rendered = 0;
+ var counter_rows_removed = 0;
+
+ // These two variables work around a bug with inertial scrolling in Webkit/Blink on Mac.
+ // See http://crbug.com/312427.
+ var rowNodeFromLastMouseWheelEvent; // this node must not be deleted while inertial scrolling
+ var zombieRowNodeFromLastMouseWheelEvent; // node that was hidden instead of getting deleted
+ var zombieRowCacheFromLastMouseWheelEvent; // row cache for above node
+ var zombieRowPostProcessedFromLastMouseWheelEvent; // post processing references for above node
+
+ // store css attributes if display:none is active in container or parent
+ var cssShow = { position: 'absolute', visibility: 'hidden', display: 'block' };
+ var $hiddenParents;
+ var oldProps = [];
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Initialization
+
+ function init() {
+ if (container instanceof jQuery) {
+ $container = container;
+ } else {
+ $container = $(container);
+ }
+ if ($container.length < 1) {
+ throw new Error("SlickGrid requires a valid container, " + container + " does not exist in the DOM.");
+ }
+
+ cacheCssForHiddenInit();
+
+ // calculate these only once and share between grid instances
+ maxSupportedCssHeight = maxSupportedCssHeight || getMaxSupportedCssHeight();
+ scrollbarDimensions = scrollbarDimensions || measureScrollbar();
+
+ options = $.extend({}, defaults, options);
+ validateAndEnforceOptions();
+ columnDefaults.width = options.defaultColumnWidth;
+
+ columnsById = {};
+ for (var i = 0; i < columns.length; i++) {
+ var m = columns[i] = $.extend({}, columnDefaults, columns[i]);
+ columnsById[m.id] = i;
+ if (m.minWidth && m.width < m.minWidth) {
+ m.width = m.minWidth;
+ }
+ if (m.maxWidth && m.width > m.maxWidth) {
+ m.width = m.maxWidth;
+ }
+ }
+
+ // validate loaded JavaScript modules against requested options
+ if (options.enableColumnReorder && !$.fn.sortable) {
+ throw new Error("SlickGrid's 'enableColumnReorder = true' option requires jquery-ui.sortable module to be loaded");
+ }
+
+ editController = {
+ "commitCurrentEdit": commitCurrentEdit,
+ "cancelCurrentEdit": cancelCurrentEdit
+ };
+
+ $container
+ .empty()
+ .css("overflow", "hidden")
+ .css("outline", 0)
+ .addClass(uid)
+ .addClass("ui-widget");
+
+ // set up a positioning container if needed
+ if (!/relative|absolute|fixed/.test($container.css("position"))) {
+ $container.css("position", "relative");
+ }
+
+ $focusSink = $("<div tabIndex='0' hideFocus style='position:fixed;width:0;height:0;top:0;left:0;outline:0;'></div>").appendTo($container);
+
+ $headerScroller = $("<div class='slick-header ui-state-default' style='overflow:hidden;position:relative;' />").appendTo($container);
+ $headers = $("<div class='slick-header-columns' style='left:-1000px' />").appendTo($headerScroller);
+ $headers.width(getHeadersWidth());
+
+ $headerRowScroller = $("<div class='slick-headerrow ui-state-default' style='overflow:hidden;position:relative;' />").appendTo($container);
+ $headerRow = $("<div class='slick-headerrow-columns' />").appendTo($headerRowScroller);
+ $headerRowSpacer = $("<div style='display:block;height:1px;position:absolute;top:0;left:0;'></div>")
+ .css("width", getCanvasWidth() + scrollbarDimensions.width + "px")
+ .appendTo($headerRowScroller);
+
+ $topPanelScroller = $("<div class='slick-top-panel-scroller ui-state-default' style='overflow:hidden;position:relative;' />").appendTo($container);
+ $topPanel = $("<div class='slick-top-panel' style='width:10000px' />").appendTo($topPanelScroller);
+
+ if (!options.showTopPanel) {
+ $topPanelScroller.hide();
+ }
+
+ if (!options.showHeaderRow) {
+ $headerRowScroller.hide();
+ }
+
+ $viewport = $("<div class='slick-viewport' style='width:100%;overflow:auto;outline:0;position:relative;;'>").appendTo($container);
+ $viewport.css("overflow-y", options.autoHeight ? "hidden" : "auto");
+
+ $canvas = $("<div class='grid-canvas' />").appendTo($viewport);
+
+ if (options.createFooterRow) {
+ $footerRowScroller = $("<div class='slick-footerrow ui-state-default' style='overflow:hidden;position:relative;' />").appendTo($container);
+ $footerRow = $("<div class='slick-footerrow-columns' />").appendTo($footerRowScroller);
+ $footerRowSpacer = $("<div style='display:block;height:1px;position:absolute;top:0;left:0;'></div>")
+ .css("width", getCanvasWidth() + scrollbarDimensions.width + "px")
+ .appendTo($footerRowScroller);
+
+ if (!options.showFooterRow) {
+ $footerRowScroller.hide();
+ }
+ }
+
+ if (options.numberedMultiColumnSort) { sortIndicatorCssClass = "slick-sort-indicator-numbered"; }
+
+ $focusSink2 = $focusSink.clone().appendTo($container);
+
+ if (!options.explicitInitialization) {
+ finishInitialization();
+ }
+ }
+
+ function finishInitialization() {
+ if (!initialized) {
+ initialized = true;
+
+ viewportW = parseFloat($.css($container[0], "width", true));
+
+ // header columns and cells may have different padding/border skewing width calculations (box-sizing, hello?)
+ // calculate the diff so we can set consistent sizes
+ measureCellPaddingAndBorder();
+
+ // for usability reasons, all text selection in SlickGrid is disabled
+ // with the exception of input and textarea elements (selection must
+ // be enabled there so that editors work as expected); note that
+ // selection in grid cells (grid body) is already unavailable in
+ // all browsers except IE
+ disableSelection($headers); // disable all text selection in header (including input and textarea)
+
+ if (!options.enableTextSelectionOnCells) {
+ // disable text selection in grid cells except in input and textarea elements
+ // (this is IE-specific, because selectstart event will only fire in IE)
+ $viewport.on("selectstart.ui", function (event) {
+ return $(event.target).is("input,textarea");
+ });
+ }
+
+ updateColumnCaches();
+ createColumnHeaders();
+ setupColumnSort();
+ createCssRules();
+ resizeCanvas();
+ bindAncestorScrollEvents();
+
+ $container
+ .on("resize.slickgrid", resizeCanvas);
+ $viewport
+ //.on("click", handleClick)
+ .on("scroll", handleScroll);
+ $headerScroller
+ .on("contextmenu", handleHeaderContextMenu)
+ .on("click", handleHeaderClick)
+ .on("mouseenter", ".slick-header-column", handleHeaderMouseEnter)
+ .on("mouseleave", ".slick-header-column", handleHeaderMouseLeave);
+ $headerRowScroller
+ .on("scroll", handleHeaderRowScroll);
+
+ if (options.createFooterRow) {
+ $footerRowScroller
+ .on("scroll", handleFooterRowScroll);
+ }
+
+ $focusSink.add($focusSink2)
+ .on("keydown", handleKeyDown);
+ $canvas
+ .on("keydown", handleKeyDown)
+ .on("click", handleClick)
+ .on("dblclick", handleDblClick)
+ .on("contextmenu", handleContextMenu)
+ .on("draginit", handleDragInit)
+ .on("dragstart", {distance: 3}, handleDragStart)
+ .on("drag", handleDrag)
+ .on("dragend", handleDragEnd)
+ .on("mouseenter", ".slick-cell", handleMouseEnter)
+ .on("mouseleave", ".slick-cell", handleMouseLeave);
+
+ // Work around http://crbug.com/312427.
+ if (navigator.userAgent.toLowerCase().match(/webkit/) &&
+ navigator.userAgent.toLowerCase().match(/macintosh/)) {
+ $canvas.on("mousewheel", handleMouseWheel);
+ }
+ restoreCssFromHiddenInit();
+ }
+ }
+
+ function cacheCssForHiddenInit() {
+ // handle display:none on container or container parents
+ $hiddenParents = $container.parents().addBack().not(':visible');
+ $hiddenParents.each(function() {
+ var old = {};
+ for ( var name in cssShow ) {
+ old[ name ] = this.style[ name ];
+ this.style[ name ] = cssShow[ name ];
+ }
+ oldProps.push(old);
+ });
+ }
+
+ function restoreCssFromHiddenInit() {
+ // finish handle display:none on container or container parents
+ // - put values back the way they were
+ $hiddenParents.each(function(i) {
+ var old = oldProps[i];
+ for ( var name in cssShow ) {
+ this.style[ name ] = old[ name ];
+ }
+ });
+ }
+
+ function registerPlugin(plugin) {
+ plugins.unshift(plugin);
+ plugin.init(self);
+ }
+
+ function unregisterPlugin(plugin) {
+ for (var i = plugins.length; i >= 0; i--) {
+ if (plugins[i] === plugin) {
+ if (plugins[i].destroy) {
+ plugins[i].destroy();
+ }
+ plugins.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ function setSelectionModel(model) {
+ if (selectionModel) {
+ selectionModel.onSelectedRangesChanged.unsubscribe(handleSelectedRangesChanged);
+ if (selectionModel.destroy) {
+ selectionModel.destroy();
+ }
+ }
+
+ selectionModel = model;
+ if (selectionModel) {
+ selectionModel.init(self);
+ selectionModel.onSelectedRangesChanged.subscribe(handleSelectedRangesChanged);
+ }
+ }
+
+ function getSelectionModel() {
+ return selectionModel;
+ }
+
+ function getCanvasNode() {
+ return $canvas[0];
+ }
+
+ function measureScrollbar() {
+ var $c = $("<div style='position:absolute; top:-10000px; left:-10000px; width:100px; height:100px; overflow:scroll;'></div>").appendTo("body");
+ var dim = {
+ width: $c.width() - $c[0].clientWidth,
+ height: $c.height() - $c[0].clientHeight
+ };
+ $c.remove();
+ return dim;
+ }
+
+ function getHeadersWidth() {
+ var headersWidth = 0;
+ for (var i = 0, ii = columns.length; i < ii; i++) {
+ var width = columns[i].width;
+ headersWidth += width;
+ }
+ headersWidth += scrollbarDimensions.width;
+ return Math.max(headersWidth, viewportW) + 1000;
+ }
+
+ function getCanvasWidth() {
+ var availableWidth = viewportHasVScroll ? viewportW - scrollbarDimensions.width : viewportW;
+ var rowWidth = 0;
+ var i = columns.length;
+ while (i--) {
+ rowWidth += columns[i].width;
+ }
+ return options.fullWidthRows ? Math.max(rowWidth, availableWidth) : rowWidth;
+ }
+
+ function updateCanvasWidth(forceColumnWidthsUpdate) {
+ var oldCanvasWidth = canvasWidth;
+ canvasWidth = getCanvasWidth();
+
+ if (canvasWidth != oldCanvasWidth) {
+ $canvas.width(canvasWidth);
+ $headerRow.width(canvasWidth);
+ if (options.createFooterRow) { $footerRow.width(canvasWidth); }
+ $headers.width(getHeadersWidth());
+ viewportHasHScroll = (canvasWidth > viewportW - scrollbarDimensions.width);
+ }
+
+ var w=canvasWidth + (viewportHasVScroll ? scrollbarDimensions.width : 0);
+ $headerRowSpacer.width(w);
+ if (options.createFooterRow) { $footerRowSpacer.width(w); }
+
+ if (canvasWidth != oldCanvasWidth || forceColumnWidthsUpdate) {
+ applyColumnWidths();
+ }
+ }
+
+ function disableSelection($target) {
+ if ($target && $target.jquery) {
+ $target
+ .attr("unselectable", "on")
+ .css("MozUserSelect", "none")
+ .on("selectstart.ui", function () {
+ return false;
+ }); // from jquery:ui.core.js 1.7.2
+ }
+ }
+
+ function getMaxSupportedCssHeight() {
+ var supportedHeight = 1000000;
+ // FF reports the height back but still renders blank after ~6M px
+ var testUpTo = navigator.userAgent.toLowerCase().match(/firefox/) ? 6000000 : 1000000000;
+ var div = $("<div style='display:none' />").appendTo(document.body);
+
+ while (true) {
+ var test = supportedHeight * 2;
+ div.css("height", test);
+ if (test > testUpTo || div.height() !== test) {
+ break;
+ } else {
+ supportedHeight = test;
+ }
+ }
+
+ div.remove();
+ return supportedHeight;
+ }
+
+ // TODO: this is static. need to handle page mutation.
+ function bindAncestorScrollEvents() {
+ var elem = $canvas[0];
+ while ((elem = elem.parentNode) != document.body && elem != null) {
+ // bind to scroll containers only
+ if (elem == $viewport[0] || elem.scrollWidth != elem.clientWidth || elem.scrollHeight != elem.clientHeight) {
+ var $elem = $(elem);
+ if (!$boundAncestors) {
+ $boundAncestors = $elem;
+ } else {
+ $boundAncestors = $boundAncestors.add($elem);
+ }
+ $elem.on("scroll." + uid, handleActiveCellPositionChange);
+ }
+ }
+ }
+
+ function unbindAncestorScrollEvents() {
+ if (!$boundAncestors) {
+ return;
+ }
+ $boundAncestors.off("scroll." + uid);
+ $boundAncestors = null;
+ }
+
+ function updateColumnHeader(columnId, title, toolTip) {
+ if (!initialized) { return; }
+ var idx = getColumnIndex(columnId);
+ if (idx == null) {
+ return;
+ }
+
+ var columnDef = columns[idx];
+ var $header = $headers.children().eq(idx);
+ if ($header) {
+ if (title !== undefined) {
+ columns[idx].name = title;
+ }
+ if (toolTip !== undefined) {
+ columns[idx].toolTip = toolTip;
+ }
+
+ trigger(self.onBeforeHeaderCellDestroy, {
+ "node": $header[0],
+ "column": columnDef,
+ "grid": self
+ });
+
+ $header
+ .attr("title", toolTip || "")
+ .children().eq(0).html(title);
+
+ trigger(self.onHeaderCellRendered, {
+ "node": $header[0],
+ "column": columnDef,
+ "grid": self
+ });
+ }
+ }
+
+ function getHeaderRow() {
+ return $headerRow[0];
+ }
+
+ function getFooterRow() {
+ return $footerRow[0];
+ }
+
+ function getHeaderRowColumn(columnId) {
+ var idx = getColumnIndex(columnId);
+ var $header = $headerRow.children().eq(idx);
+ return $header && $header[0];
+ }
+
+ function getFooterRowColumn(columnId) {
+ var idx = getColumnIndex(columnId);
+ var $footer = $footerRow.children().eq(idx);
+ return $footer && $footer[0];
+ }
+
+ function createColumnHeaders() {
+ function onMouseEnter() {
+ $(this).addClass("ui-state-hover");
+ }
+
+ function onMouseLeave() {
+ $(this).removeClass("ui-state-hover");
+ }
+
+ $headers.find(".slick-header-column")
+ .each(function() {
+ var columnDef = $(this).data("column");
+ if (columnDef) {
+ trigger(self.onBeforeHeaderCellDestroy, {
+ "node": this,
+ "column": columnDef,
+ "grid": self
+ });
+ }
+ });
+ $headers.empty();
+ $headers.width(getHeadersWidth());
+
+ $headerRow.find(".slick-headerrow-column")
+ .each(function() {
+ var columnDef = $(this).data("column");
+ if (columnDef) {
+ trigger(self.onBeforeHeaderRowCellDestroy, {
+ "node": this,
+ "column": columnDef,
+ "grid": self
+ });
+ }
+ });
+ $headerRow.empty();
+
+ if (options.createFooterRow) {
+ $footerRow.find(".slick-footerrow-column")
+ .each(function() {
+ var columnDef = $(this).data("column");
+ if (columnDef) {
+ trigger(self.onBeforeFooterRowCellDestroy, {
+ "node": this,
+ "column": columnDef
+ });
+ }
+ });
+ $footerRow.empty();
+ }
+
+ for (var i = 0; i < columns.length; i++) {
+ var m = columns[i];
+
+ var header = $("<div class='ui-state-default slick-header-column' />")
+ .html("<span class='slick-column-name'>" + m.name + "</span>")
+ .width(m.width - headerColumnWidthDiff)
+ .attr("id", "" + uid + m.id)
+ .attr("title", m.toolTip || "")
+ .data("column", m)
+ .addClass(m.headerCssClass || "")
+ .appendTo($headers);
+
+ if (options.enableColumnReorder || m.sortable) {
+ header
+ .on('mouseenter', onMouseEnter)
+ .on('mouseleave', onMouseLeave);
+ }
+
+ if (m.sortable) {
+ header.addClass("slick-header-sortable");
+ header.append("<span class='" + sortIndicatorCssClass + "' />");
+ }
+
+ trigger(self.onHeaderCellRendered, {
+ "node": header[0],
+ "column": m,
+ "grid": self
+ });
+
+ if (options.showHeaderRow) {
+ var headerRowCell = $("<div class='ui-state-default slick-headerrow-column l" + i + " r" + i + "'></div>")
+ .data("column", m)
+ .appendTo($headerRow);
+
+ trigger(self.onHeaderRowCellRendered, {
+ "node": headerRowCell[0],
+ "column": m,
+ "grid": self
+ });
+ }
+ if (options.createFooterRow && options.showFooterRow) {
+ var footerRowCell = $("<div class='ui-state-default slick-footerrow-column l" + i + " r" + i + "'></div>")
+ .data("column", m)
+ .appendTo($footerRow);
+
+ trigger(self.onFooterRowCellRendered, {
+ "node": footerRowCell[0],
+ "column": m
+ });
+ }
+ }
+
+ setSortColumns(sortColumns);
+ setupColumnResize();
+ if (options.enableColumnReorder) {
+ setupColumnReorder();
+ }
+ }
+
+ function setupColumnSort() {
+ $headers.click(function (e) {
+ // temporary workaround for a bug in jQuery 1.7.1 (http://bugs.jquery.com/ticket/11328)
+ e.metaKey = e.metaKey || e.ctrlKey;
+
+ if ($(e.target).hasClass("slick-resizable-handle")) {
+ return;
+ }
+
+ var $col = $(e.target).closest(".slick-header-column");
+ if (!$col.length) {
+ return;
+ }
+
+ var column = $col.data("column");
+ if (column.sortable) {
+ if (!getEditorLock().commitCurrentEdit()) {
+ return;
+ }
+
+ var sortColumn = null;
+ var i = 0;
+ for (; i < sortColumns.length; i++) {
+ if (sortColumns[i].columnId == column.id) {
+ sortColumn = sortColumns[i];
+ sortColumn.sortAsc = !sortColumn.sortAsc;
+ break;
+ }
+ }
+ var hadSortCol = !!sortColumn;
+
+ if (options.tristateMultiColumnSort) {
+ if (!sortColumn) {
+ sortColumn = { columnId: column.id, sortAsc: column.defaultSortAsc };
+ }
+ if (hadSortCol && sortColumn.sortAsc) {
+ // three state: remove sort rather than go back to ASC
+ sortColumns.splice(i, 1);
+ sortColumn = null;
+ }
+ if (!options.multiColumnSort) { sortColumns = []; }
+ if (sortColumn && (!hadSortCol || !options.multiColumnSort)) {
+ sortColumns.push(sortColumn);
+ }
+ } else {
+ // legacy behaviour
+ if (e.metaKey && options.multiColumnSort) {
+ if (sortColumn) {
+ sortColumns.splice(i, 1);
+ }
+ }
+ else {
+ if ((!e.shiftKey && !e.metaKey) || !options.multiColumnSort) {
+ sortColumns = [];
+ }
+
+ if (!sortColumn) {
+ sortColumn = { columnId: column.id, sortAsc: column.defaultSortAsc };
+ sortColumns.push(sortColumn);
+ } else if (sortColumns.length == 0) {
+ sortColumns.push(sortColumn);
+ }
+ }
+ }
+
+ setSortColumns(sortColumns);
+
+ if (sortColumns.length > 0) {
+ if (!options.multiColumnSort) {
+ trigger(self.onSort, {
+ multiColumnSort: false,
+ sortCol: column,
+ sortAsc: sortColumns[0].sortAsc,
+ grid: self}, e);
+ } else {
+ trigger(self.onSort, {
+ multiColumnSort: true,
+ sortCols: $.map(sortColumns, function(col) {
+ return {sortCol: columns[getColumnIndex(col.columnId)], sortAsc: col.sortAsc };
+ }),
+ grid: self}, e);
+ }
+ }
+ }
+ });
+ }
+
+ function setupColumnReorder() {
+ $headers.filter(":ui-sortable").sortable("destroy");
+ $headers.sortable({
+ containment: "parent",
+ distance: 3,
+ axis: "x",
+ cursor: "default",
+ tolerance: "intersection",
+ helper: "clone",
+ placeholder: "slick-sortable-placeholder ui-state-default slick-header-column",
+ start: function (e, ui) {
+ ui.placeholder.width(ui.helper.outerWidth() - headerColumnWidthDiff);
+ $(ui.helper).addClass("slick-header-column-active");
+ },
+ beforeStop: function (e, ui) {
+ $(ui.helper).removeClass("slick-header-column-active");
+ },
+ stop: function (e) {
+ if (!getEditorLock().commitCurrentEdit()) {
+ $(this).sortable("cancel");
+ return;
+ }
+
+ var reorderedIds = $headers.sortable("toArray");
+ var reorderedColumns = [];
+ for (var i = 0; i < reorderedIds.length; i++) {
+ reorderedColumns.push(columns[getColumnIndex(reorderedIds[i].replace(uid, ""))]);
+ }
+ setColumns(reorderedColumns);
+
+ trigger(self.onColumnsReordered, {grid: self});
+ e.stopPropagation();
+ setupColumnResize();
+ }
+ });
+ }
+
+ function setupColumnResize() {
+ var $col, j, c, pageX, columnElements, minPageX, maxPageX, firstResizable, lastResizable;
+ columnElements = $headers.children();
+ columnElements.find(".slick-resizable-handle").remove();
+ columnElements.each(function (i, e) {
+ if (columns[i].resizable) {
+ if (firstResizable === undefined) {
+ firstResizable = i;
+ }
+ lastResizable = i;
+ }
+ });
+ if (firstResizable === undefined) {
+ return;
+ }
+ columnElements.each(function (i, e) {
+ if (i < firstResizable || (options.forceFitColumns && i >= lastResizable)) {
+ return;
+ }
+ $col = $(e);
+ $("<div class='slick-resizable-handle' />")
+ .appendTo(e)
+ .on("dragstart", function (e, dd) {
+ if (!getEditorLock().commitCurrentEdit()) {
+ return false;
+ }
+ pageX = e.pageX;
+ $(this).parent().addClass("slick-header-column-active");
+ var shrinkLeewayOnRight = null, stretchLeewayOnRight = null;
+ // lock each column's width option to current width
+ columnElements.each(function (i, e) {
+ columns[i].previousWidth = $(e).outerWidth();
+ });
+ if (options.forceFitColumns) {
+ shrinkLeewayOnRight = 0;
+ stretchLeewayOnRight = 0;
+ // colums on right affect maxPageX/minPageX
+ for (j = i + 1; j < columnElements.length; j++) {
+ c = columns[j];
+ if (c.resizable) {
+ if (stretchLeewayOnRight !== null) {
+ if (c.maxWidth) {
+ stretchLeewayOnRight += c.maxWidth - c.previousWidth;
+ } else {
+ stretchLeewayOnRight = null;
+ }
+ }
+ shrinkLeewayOnRight += c.previousWidth - Math.max(c.minWidth || 0, absoluteColumnMinWidth);
+ }
+ }
+ }
+ var shrinkLeewayOnLeft = 0, stretchLeewayOnLeft = 0;
+ for (j = 0; j <= i; j++) {
+ // columns on left only affect minPageX
+ c = columns[j];
+ if (c.resizable) {
+ if (stretchLeewayOnLeft !== null) {
+ if (c.maxWidth) {
+ stretchLeewayOnLeft += c.maxWidth - c.previousWidth;
+ } else {
+ stretchLeewayOnLeft = null;
+ }
+ }
+ shrinkLeewayOnLeft += c.previousWidth - Math.max(c.minWidth || 0, absoluteColumnMinWidth);
+ }
+ }
+ if (shrinkLeewayOnRight === null) {
+ shrinkLeewayOnRight = 100000;
+ }
+ if (shrinkLeewayOnLeft === null) {
+ shrinkLeewayOnLeft = 100000;
+ }
+ if (stretchLeewayOnRight === null) {
+ stretchLeewayOnRight = 100000;
+ }
+ if (stretchLeewayOnLeft === null) {
+ stretchLeewayOnLeft = 100000;
+ }
+ maxPageX = pageX + Math.min(shrinkLeewayOnRight, stretchLeewayOnLeft);
+ minPageX = pageX - Math.min(shrinkLeewayOnLeft, stretchLeewayOnRight);
+ })
+ .on("drag", function (e, dd) {
+ var actualMinWidth, d = Math.min(maxPageX, Math.max(minPageX, e.pageX)) - pageX, x;
+ if (d < 0) { // shrink column
+ x = d;
+ for (j = i; j >= 0; j--) {
+ c = columns[j];
+ if (c.resizable) {
+ actualMinWidth = Math.max(c.minWidth || 0, absoluteColumnMinWidth);
+ if (x && c.previousWidth + x < actualMinWidth) {
+ x += c.previousWidth - actualMinWidth;
+ c.width = actualMinWidth;
+ } else {
+ c.width = c.previousWidth + x;
+ x = 0;
+ }
+ }
+ }
+
+ if (options.forceFitColumns) {
+ x = -d;
+ for (j = i + 1; j < columnElements.length; j++) {
+ c = columns[j];
+ if (c.resizable) {
+ if (x && c.maxWidth && (c.maxWidth - c.previousWidth < x)) {
+ x -= c.maxWidth - c.previousWidth;
+ c.width = c.maxWidth;
+ } else {
+ c.width = c.previousWidth + x;
+ x = 0;
+ }
+ }
+ }
+ }
+ } else { // stretch column
+ x = d;
+ for (j = i; j >= 0; j--) {
+ c = columns[j];
+ if (c.resizable) {
+ if (x && c.maxWidth && (c.maxWidth - c.previousWidth < x)) {
+ x -= c.maxWidth - c.previousWidth;
+ c.width = c.maxWidth;
+ } else {
+ c.width = c.previousWidth + x;
+ x = 0;
+ }
+ }
+ }
+
+ if (options.forceFitColumns) {
+ x = -d;
+ for (j = i + 1; j < columnElements.length; j++) {
+ c = columns[j];
+ if (c.resizable) {
+ actualMinWidth = Math.max(c.minWidth || 0, absoluteColumnMinWidth);
+ if (x && c.previousWidth + x < actualMinWidth) {
+ x += c.previousWidth - actualMinWidth;
+ c.width = actualMinWidth;
+ } else {
+ c.width = c.previousWidth + x;
+ x = 0;
+ }
+ }
+ }
+ }
+ }
+ applyColumnHeaderWidths();
+ if (options.syncColumnCellResize) {
+ applyColumnWidths();
+ }
+ })
+ .on("dragend", function (e, dd) {
+ var newWidth;
+ $(this).parent().removeClass("slick-header-column-active");
+ for (j = 0; j < columnElements.length; j++) {
+ c = columns[j];
+ newWidth = $(columnElements[j]).outerWidth();
+
+ if (c.previousWidth !== newWidth && c.rerenderOnResize) {
+ invalidateAllRows();
+ }
+ }
+ updateCanvasWidth(true);
+ render();
+ trigger(self.onColumnsResized, {grid: self});
+ });
+ });
+ }
+
+ function getVBoxDelta($el) {
+ var p = ["borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom"];
+ var delta = 0;
+ $.each(p, function (n, val) {
+ delta += parseFloat($el.css(val)) || 0;
+ });
+ return delta;
+ }
+
+ function measureCellPaddingAndBorder() {
+ var el;
+ var h = ["borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight"];
+ var v = ["borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom"];
+
+ // jquery prior to version 1.8 handles .width setter/getter as a direct css write/read
+ // jquery 1.8 changed .width to read the true inner element width if box-sizing is set to border-box, and introduced a setter for .outerWidth
+ // so for equivalent functionality, prior to 1.8 use .width, and after use .outerWidth
+ var verArray = $.fn.jquery.split('.');
+ jQueryNewWidthBehaviour = (verArray[0]==1 && verArray[1]>=8) || verArray[0] >=2;
+
+ el = $("<div class='ui-state-default slick-header-column' style='visibility:hidden'>-</div>").appendTo($headers);
+ headerColumnWidthDiff = headerColumnHeightDiff = 0;
+ if (el.css("box-sizing") != "border-box" && el.css("-moz-box-sizing") != "border-box" && el.css("-webkit-box-sizing") != "border-box") {
+ $.each(h, function (n, val) {
+ headerColumnWidthDiff += parseFloat(el.css(val)) || 0;
+ });
+ $.each(v, function (n, val) {
+ headerColumnHeightDiff += parseFloat(el.css(val)) || 0;
+ });
+ }
+ el.remove();
+
+ var r = $("<div class='slick-row' />").appendTo($canvas);
+ el = $("<div class='slick-cell' id='' style='visibility:hidden'>-</div>").appendTo(r);
+ cellWidthDiff = cellHeightDiff = 0;
+ if (el.css("box-sizing") != "border-box" && el.css("-moz-box-sizing") != "border-box" && el.css("-webkit-box-sizing") != "border-box") {
+ $.each(h, function (n, val) {
+ cellWidthDiff += parseFloat(el.css(val)) || 0;
+ });
+ $.each(v, function (n, val) {
+ cellHeightDiff += parseFloat(el.css(val)) || 0;
+ });
+ }
+ r.remove();
+
+ absoluteColumnMinWidth = Math.max(headerColumnWidthDiff, cellWidthDiff);
+ }
+
+ function createCssRules() {
+ $style = $("<style type='text/css' rel='stylesheet' />").appendTo($("head"));
+ var rowHeight = (options.rowHeight - cellHeightDiff);
+ var rules = [
+ "." + uid + " .slick-header-column { left: 1000px; }",
+ "." + uid + " .slick-top-panel { height:" + options.topPanelHeight + "px; }",
+ "." + uid + " .slick-headerrow-columns { height:" + options.headerRowHeight + "px; }",
+ "." + uid + " .slick-footerrow-columns { height:" + options.footerRowHeight + "px; }",
+ "." + uid + " .slick-cell { height:" + rowHeight + "px; }",
+ "." + uid + " .slick-row { height:" + options.rowHeight + "px; }"
+ ];
+
+ for (var i = 0; i < columns.length; i++) {
+ rules.push("." + uid + " .l" + i + " { }");
+ rules.push("." + uid + " .r" + i + " { }");
+ }
+
+ if ($style[0].styleSheet) { // IE
+ $style[0].styleSheet.cssText = rules.join(" ");
+ } else {
+ $style[0].appendChild(document.createTextNode(rules.join(" ")));
+ }
+ }
+
+ function getColumnCssRules(idx) {
+ var i;
+ if (!stylesheet) {
+ var sheets = document.styleSheets;
+ for (i = 0; i < sheets.length; i++) {
+ if ((sheets[i].ownerNode || sheets[i].owningElement) == $style[0]) {
+ stylesheet = sheets[i];
+ break;
+ }
+ }
+
+ if (!stylesheet) {
+ throw new Error("Cannot find stylesheet.");
+ }
+
+ // find and cache column CSS rules
+ columnCssRulesL = [];
+ columnCssRulesR = [];
+ var cssRules = (stylesheet.cssRules || stylesheet.rules);
+ var matches, columnIdx;
+ for (i = 0; i < cssRules.length; i++) {
+ var selector = cssRules[i].selectorText;
+ if (matches = /\.l\d+/.exec(selector)) {
+ columnIdx = parseInt(matches[0].substr(2, matches[0].length - 2), 10);
+ columnCssRulesL[columnIdx] = cssRules[i];
+ } else if (matches = /\.r\d+/.exec(selector)) {
+ columnIdx = parseInt(matches[0].substr(2, matches[0].length - 2), 10);
+ columnCssRulesR[columnIdx] = cssRules[i];
+ }
+ }
+ }
+
+ return {
+ "left": columnCssRulesL[idx],
+ "right": columnCssRulesR[idx]
+ };
+ }
+
+ function removeCssRules() {
+ $style.remove();
+ stylesheet = null;
+ }
+
+ function destroy() {
+ getEditorLock().cancelCurrentEdit();
+
+ trigger(self.onBeforeDestroy, {grid: self});
+
+ var i = plugins.length;
+ while(i--) {
+ unregisterPlugin(plugins[i]);
+ }
+
+ if (options.enableColumnReorder) {
+ $headers.filter(":ui-sortable").sortable("destroy");
+ }
+
+ unbindAncestorScrollEvents();
+ $container.off(".slickgrid");
+ removeCssRules();
+
+ $canvas.off("draginit dragstart dragend drag");
+ $container.empty().removeClass(uid);
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // General
+
+ function trigger(evt, args, e) {
+ e = e || new Slick.EventData();
+ args = args || {};
+ args.grid = self;
+ return evt.notify(args, e, self);
+ }
+
+ function getEditorLock() {
+ return options.editorLock;
+ }
+
+ function getEditController() {
+ return editController;
+ }
+
+ function getColumnIndex(id) {
+ return columnsById[id];
+ }
+
+ function autosizeColumns() {
+ var i, c,
+ widths = [],
+ shrinkLeeway = 0,
+ total = 0,
+ prevTotal,
+ availWidth = viewportHasVScroll ? viewportW - scrollbarDimensions.width : viewportW;
+
+ for (i = 0; i < columns.length; i++) {
+ c = columns[i];
+ widths.push(c.width);
+ total += c.width;
+ if (c.resizable) {
+ shrinkLeeway += c.width - Math.max(c.minWidth, absoluteColumnMinWidth);
+ }
+ }
+
+ // shrink
+ prevTotal = total;
+ while (total > availWidth && shrinkLeeway) {
+ var shrinkProportion = (total - availWidth) / shrinkLeeway;
+ for (i = 0; i < columns.length && total > availWidth; i++) {
+ c = columns[i];
+ var width = widths[i];
+ if (!c.resizable || width <= c.minWidth || width <= absoluteColumnMinWidth) {
+ continue;
+ }
+ var absMinWidth = Math.max(c.minWidth, absoluteColumnMinWidth);
+ var shrinkSize = Math.floor(shrinkProportion * (width - absMinWidth)) || 1;
+ shrinkSize = Math.min(shrinkSize, width - absMinWidth);
+ total -= shrinkSize;
+ shrinkLeeway -= shrinkSize;
+ widths[i] -= shrinkSize;
+ }
+ if (prevTotal <= total) { // avoid infinite loop
+ break;
+ }
+ prevTotal = total;
+ }
+
+ // grow
+ prevTotal = total;
+ while (total < availWidth) {
+ var growProportion = availWidth / total;
+ for (i = 0; i < columns.length && total < availWidth; i++) {
+ c = columns[i];
+ var currentWidth = widths[i];
+ var growSize;
+
+ if (!c.resizable || c.maxWidth <= currentWidth) {
+ growSize = 0;
+ } else {
+ growSize = Math.min(Math.floor(growProportion * currentWidth) - currentWidth, (c.maxWidth - currentWidth) || 1000000) || 1;
+ }
+ total += growSize;
+ widths[i] += (total <= availWidth ? growSize : 0);
+ }
+ if (prevTotal >= total) { // avoid infinite loop
+ break;
+ }
+ prevTotal = total;
+ }
+
+ var reRender = false;
+ for (i = 0; i < columns.length; i++) {
+ if (columns[i].rerenderOnResize && columns[i].width != widths[i]) {
+ reRender = true;
+ }
+ columns[i].width = widths[i];
+ }
+
+ applyColumnHeaderWidths();
+ updateCanvasWidth(true);
+ if (reRender) {
+ invalidateAllRows();
+ render();
+ }
+ }
+
+ function applyColumnHeaderWidths() {
+ if (!initialized) { return; }
+ var h;
+ for (var i = 0, headers = $headers.children(), ii = headers.length; i < ii; i++) {
+ h = $(headers[i]);
+ if (jQueryNewWidthBehaviour) {
+ if (h.outerWidth() !== columns[i].width) {
+ h.outerWidth(columns[i].width);
+ }
+ } else {
+ if (h.width() !== columns[i].width - headerColumnWidthDiff) {
+ h.width(columns[i].width - headerColumnWidthDiff);
+ }
+ }
+ }
+
+ updateColumnCaches();
+ }
+
+ function applyColumnWidths() {
+ var x = 0, w, rule;
+ for (var i = 0; i < columns.length; i++) {
+ w = columns[i].width;
+
+ rule = getColumnCssRules(i);
+ rule.left.style.left = x + "px";
+ rule.right.style.right = (canvasWidth - x - w) + "px";
+
+ x += columns[i].width;
+ }
+ }
+
+ function setSortColumn(columnId, ascending) {
+ setSortColumns([{ columnId: columnId, sortAsc: ascending}]);
+ }
+
+ function setSortColumns(cols) {
+ sortColumns = cols;
+ var numberCols = options.numberedMultiColumnSort && sortColumns.length > 1;
+ var headerColumnEls = $headers.children();
+ var sortIndicatorEl = headerColumnEls
+ .removeClass("slick-header-column-sorted")
+ .find("." + sortIndicatorCssClass)
+ .removeClass("slick-sort-indicator-asc slick-sort-indicator-desc");
+ if (numberCols) { sortIndicatorEl.text(''); }
+
+ $.each(sortColumns, function(i, col) {
+ if (col.sortAsc == null) {
+ col.sortAsc = true;
+ }
+ var columnIndex = getColumnIndex(col.columnId);
+ if (columnIndex != null) {
+ sortIndicatorEl = headerColumnEls.eq(columnIndex)
+ .addClass("slick-header-column-sorted")
+ .find("." + sortIndicatorCssClass)
+ .addClass(col.sortAsc ? "slick-sort-indicator-asc" : "slick-sort-indicator-desc");
+ if (numberCols) { sortIndicatorEl.text(i+1); }
+ }
+ });
+ }
+
+ function getSortColumns() {
+ return sortColumns;
+ }
+
+ function handleSelectedRangesChanged(e, ranges) {
+ selectedRows = [];
+ var hash = {};
+ for (var i = 0; i < ranges.length; i++) {
+ for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
+ if (!hash[j]) { // prevent duplicates
+ selectedRows.push(j);
+ hash[j] = {};
+ }
+ for (var k = ranges[i].fromCell; k <= ranges[i].toCell; k++) {
+ if (canCellBeSelected(j, k)) {
+ hash[j][columns[k].id] = options.selectedCellCssClass;
+ }
+ }
+ }
+ }
+
+ setCellCssStyles(options.selectedCellCssClass, hash);
+
+ trigger(self.onSelectedRowsChanged, {rows: getSelectedRows(), grid: self}, e);
+ }
+
+ function getColumns() {
+ return columns;
+ }
+
+ function updateColumnCaches() {
+ // Pre-calculate cell boundaries.
+ columnPosLeft = [];
+ columnPosRight = [];
+ var x = 0;
+ for (var i = 0, ii = columns.length; i < ii; i++) {
+ columnPosLeft[i] = x;
+ columnPosRight[i] = x + columns[i].width;
+ x += columns[i].width;
+ }
+ }
+
+ function setColumns(columnDefinitions) {
+ columns = columnDefinitions;
+
+ columnsById = {};
+ for (var i = 0; i < columns.length; i++) {
+ var m = columns[i] = $.extend({}, columnDefaults, columns[i]);
+ columnsById[m.id] = i;
+ if (m.minWidth && m.width < m.minWidth) {
+ m.width = m.minWidth;
+ }
+ if (m.maxWidth && m.width > m.maxWidth) {
+ m.width = m.maxWidth;
+ }
+ }
+
+ updateColumnCaches();
+
+ if (initialized) {
+ invalidateAllRows();
+ createColumnHeaders();
+ removeCssRules();
+ createCssRules();
+ resizeCanvas();
+ applyColumnWidths();
+ handleScroll();
+ }
+ }
+
+ function getOptions() {
+ return options;
+ }
+
+ function setOptions(args, suppressRender) {
+ if (!getEditorLock().commitCurrentEdit()) {
+ return;
+ }
+
+ makeActiveCellNormal();
+
+ if (options.enableAddRow !== args.enableAddRow) {
+ invalidateRow(getDataLength());
+ }
+
+ options = $.extend(options, args);
+ validateAndEnforceOptions();
+
+ $viewport.css("overflow-y", options.autoHeight ? "hidden" : "auto");
+ if (!suppressRender) { render(); }
+ }
+
+ function validateAndEnforceOptions() {
+ if (options.autoHeight) {
+ options.leaveSpaceForNewRows = false;
+ }
+ }
+
+ function setData(newData, scrollToTop) {
+ data = newData;
+ invalidateAllRows();
+ updateRowCount();
+ if (scrollToTop) {
+ scrollTo(0);
+ }
+ }
+
+ function getData() {
+ return data;
+ }
+
+ function getDataLength() {
+ if (data.getLength) {
+ return data.getLength();
+ } else {
+ return data.length;
+ }
+ }
+
+ function getDataLengthIncludingAddNew() {
+ return getDataLength() + (!options.enableAddRow ? 0
+ : (!pagingActive || pagingIsLastPage ? 1 : 0)
+ );
+ }
+
+ function getDataItem(i) {
+ if (data.getItem) {
+ return data.getItem(i);
+ } else {
+ return data[i];
+ }
+ }
+
+ function getTopPanel() {
+ return $topPanel[0];
+ }
+
+ function setTopPanelVisibility(visible) {
+ if (options.showTopPanel != visible) {
+ options.showTopPanel = visible;
+ if (visible) {
+ $topPanelScroller.slideDown("fast", resizeCanvas);
+ } else {
+ $topPanelScroller.slideUp("fast", resizeCanvas);
+ }
+ }
+ }
+
+ function setHeaderRowVisibility(visible) {
+ if (options.showHeaderRow != visible) {
+ options.showHeaderRow = visible;
+ if (visible) {
+ $headerRowScroller.slideDown("fast", resizeCanvas);
+ } else {
+ $headerRowScroller.slideUp("fast", resizeCanvas);
+ }
+ }
+ }
+
+ function setFooterRowVisibility(visible) {
+ if (options.showFooterRow != visible) {
+ options.showFooterRow = visible;
+ if (visible) {
+ $footerRowScroller.slideDown("fast", resizeCanvas);
+ } else {
+ $footerRowScroller.slideUp("fast", resizeCanvas);
+ }
+ }
+ }
+
+ function getContainerNode() {
+ return $container.get(0);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Rendering / Scrolling
+
+ function getRowTop(row) {
+ return options.rowHeight * row - offset;
+ }
+
+ function getRowFromPosition(y) {
+ return Math.floor((y + offset) / options.rowHeight);
+ }
+
+ function scrollTo(y) {
+ y = Math.max(y, 0);
+ y = Math.min(y, th - viewportH + (viewportHasHScroll ? scrollbarDimensions.height : 0));
+
+ var oldOffset = offset;
+
+ page = Math.min(n - 1, Math.floor(y / ph));
+ offset = Math.round(page * cj);
+ var newScrollTop = y - offset;
+
+ if (offset != oldOffset) {
+ var range = getVisibleRange(newScrollTop);
+ cleanupRows(range);
+ updateRowPositions();
+ }
+
+ if (prevScrollTop != newScrollTop) {
+ vScrollDir = (prevScrollTop + oldOffset < newScrollTop + offset) ? 1 : -1;
+ $viewport[0].scrollTop = (lastRenderedScrollTop = scrollTop = prevScrollTop = newScrollTop);
+
+ trigger(self.onViewportChanged, {grid: self});
+ }
+ }
+
+ function defaultFormatter(row, cell, value, columnDef, dataContext) {
+ if (value == null) {
+ return "";
+ } else {
+ return (value + "").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
+ }
+ }
+
+ function getFormatter(row, column) {
+ var rowMetadata = data.getItemMetadata && data.getItemMetadata(row);
+
+ // look up by id, then index
+ var columnOverrides = rowMetadata &&
+ rowMetadata.columns &&
+ (rowMetadata.columns[column.id] || rowMetadata.columns[getColumnIndex(column.id)]);
+
+ return (columnOverrides && columnOverrides.formatter) ||
+ (rowMetadata && rowMetadata.formatter) ||
+ column.formatter ||
+ (options.formatterFactory && options.formatterFactory.getFormatter(column)) ||
+ options.defaultFormatter;
+ }
+
+ function getEditor(row, cell) {
+ var column = columns[cell];
+ var rowMetadata = data.getItemMetadata && data.getItemMetadata(row);
+ var columnMetadata = rowMetadata && rowMetadata.columns;
+
+ if (columnMetadata && columnMetadata[column.id] && columnMetadata[column.id].editor !== undefined) {
+ return columnMetadata[column.id].editor;
+ }
+ if (columnMetadata && columnMetadata[cell] && columnMetadata[cell].editor !== undefined) {
+ return columnMetadata[cell].editor;
+ }
+
+ return column.editor || (options.editorFactory && options.editorFactory.getEditor(column));
+ }
+
+ function getDataItemValueForColumn(item, columnDef) {
+ if (options.dataItemColumnValueExtractor) {
+ return options.dataItemColumnValueExtractor(item, columnDef);
+ }
+ return item[columnDef.field];
+ }
+
+ function appendRowHtml(stringArray, row, range, dataLength) {
+ var d = getDataItem(row);
+ var dataLoading = row < dataLength && !d;
+ var rowCss = "slick-row" +
+ (dataLoading ? " loading" : "") +
+ (row === activeRow ? " active" : "") +
+ (row % 2 == 1 ? " odd" : " even");
+
+ if (!d) {
+ rowCss += " " + options.addNewRowCssClass;
+ }
+
+ var metadata = data.getItemMetadata && data.getItemMetadata(row);
+
+ if (metadata && metadata.cssClasses) {
+ rowCss += " " + metadata.cssClasses;
+ }
+
+ stringArray.push("<div class='ui-widget-content " + rowCss + "' style='top:" + getRowTop(row) + "px'>");
+
+ var colspan, m;
+ for (var i = 0, ii = columns.length; i < ii; i++) {
+ m = columns[i];
+ colspan = 1;
+ if (metadata && metadata.columns) {
+ var columnData = metadata.columns[m.id] || metadata.columns[i];
+ colspan = (columnData && columnData.colspan) || 1;
+ if (colspan === "*") {
+ colspan = ii - i;
+ }
+ }
+
+ // Do not render cells outside of the viewport.
+ if (columnPosRight[Math.min(ii - 1, i + colspan - 1)] > range.leftPx) {
+ if (columnPosLeft[i] > range.rightPx) {
+ // All columns to the right are outside the range.
+ break;
+ }
+
+ appendCellHtml(stringArray, row, i, colspan, d);
+ }
+
+ if (colspan > 1) {
+ i += (colspan - 1);
+ }
+ }
+
+ stringArray.push("</div>");
+ }
+
+ function appendCellHtml(stringArray, row, cell, colspan, item) {
+ // stringArray: stringBuilder containing the HTML parts
+ // row, cell: row and column index
+ // colspan: HTML colspan
+ // item: grid data for row
+
+ var m = columns[cell];
+ var cellCss = "slick-cell l" + cell + " r" + Math.min(columns.length - 1, cell + colspan - 1) +
+ (m.cssClass ? " " + m.cssClass : "");
+ if (row === activeRow && cell === activeCell) {
+ cellCss += (" active");
+ }
+
+ // TODO: merge them together in the setter
+ for (var key in cellCssClasses) {
+ if (cellCssClasses[key][row] && cellCssClasses[key][row][m.id]) {
+ cellCss += (" " + cellCssClasses[key][row][m.id]);
+ }
+ }
+
+ var value = null;
+ if (item) { value = getDataItemValueForColumn(item, m); }
+ var formatterResult = getFormatter(row, m)(row, cell, value, m, item);
+
+ // get addl css class names from object type formatter return and from string type return of onBeforeAppendCell
+ var addlCssClasses = trigger(self.onBeforeAppendCell, { row: row, cell: cell, grid: self, value: value, dataContext: item }) || '';
+ addlCssClasses += (formatterResult.addClasses ? (addlCssClasses ? ' ' : '') + formatterResult.addClasses : '');
+
+ stringArray.push("<div class='" + cellCss + (addlCssClasses ? ' ' + addlCssClasses : '') + "'>");
+
+ // if there is a corresponding row (if not, this is the Add New row or this data hasn't been loaded yet)
+ if (item) {
+ stringArray.push(typeof formatterResult === 'string' ? formatterResult : formatterResult.text);
+ }
+
+ stringArray.push("</div>");
+
+ rowsCache[row].cellRenderQueue.push(cell);
+ rowsCache[row].cellColSpans[cell] = colspan;
+ }
+
+
+ function cleanupRows(rangeToKeep) {
+ for (var i in rowsCache) {
+ if (((i = parseInt(i, 10)) !== activeRow) && (i < rangeToKeep.top || i > rangeToKeep.bottom)) {
+ removeRowFromCache(i);
+ }
+ }
+ if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
+ }
+
+ function invalidate() {
+ updateRowCount();
+ invalidateAllRows();
+ render();
+ }
+
+ function invalidateAllRows() {
+ if (currentEditor) {
+ makeActiveCellNormal();
+ }
+ for (var row in rowsCache) {
+ removeRowFromCache(row);
+ }
+ if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
+ }
+
+ function queuePostProcessedRowForCleanup(cacheEntry, postProcessedRow, rowIdx) {
+ postProcessgroupId++;
+
+ // store and detach node for later async cleanup
+ for (var columnIdx in postProcessedRow) {
+ if (postProcessedRow.hasOwnProperty(columnIdx)) {
+ postProcessedCleanupQueue.push({
+ actionType: 'C',
+ groupId: postProcessgroupId,
+ node: cacheEntry.cellNodesByColumnIdx[ columnIdx | 0],
+ columnIdx: columnIdx | 0,
+ rowIdx: rowIdx
+ });
+ }
+ }
+ postProcessedCleanupQueue.push({
+ actionType: 'R',
+ groupId: postProcessgroupId,
+ node: cacheEntry.rowNode
+ });
+ $(cacheEntry.rowNode).detach();
+ }
+
+ function queuePostProcessedCellForCleanup(cellnode, columnIdx, rowIdx) {
+ postProcessedCleanupQueue.push({
+ actionType: 'C',
+ groupId: postProcessgroupId,
+ node: cellnode,
+ columnIdx: columnIdx,
+ rowIdx: rowIdx
+ });
+ $(cellnode).detach();
+ }
+
+ function removeRowFromCache(row) {
+ var cacheEntry = rowsCache[row];
+ if (!cacheEntry) {
+ return;
+ }
+
+ if (rowNodeFromLastMouseWheelEvent === cacheEntry.rowNode) {
+ cacheEntry.rowNode.style.display = 'none';
+ zombieRowNodeFromLastMouseWheelEvent = rowNodeFromLastMouseWheelEvent;
+ zombieRowCacheFromLastMouseWheelEvent = cacheEntry;
+ zombieRowPostProcessedFromLastMouseWheelEvent = postProcessedRows[row];
+ // ignore post processing cleanup in this case - it will be dealt with later
+ } else {
+ if (options.enableAsyncPostRenderCleanup && postProcessedRows[row]) {
+ queuePostProcessedRowForCleanup(cacheEntry, postProcessedRows[row], row);
+ } else {
+ $canvas[0].removeChild(cacheEntry.rowNode);
+ }
+ }
+
+ delete rowsCache[row];
+ delete postProcessedRows[row];
+ renderedRows--;
+ counter_rows_removed++;
+ }
+
+ function invalidateRows(rows) {
+ var i, rl;
+ if (!rows || !rows.length) {
+ return;
+ }
+ vScrollDir = 0;
+ rl = rows.length;
+ for (i = 0; i < rl; i++) {
+ if (currentEditor && activeRow === rows[i]) {
+ makeActiveCellNormal();
+ }
+ if (rowsCache[rows[i]]) {
+ removeRowFromCache(rows[i]);
+ }
+ }
+ if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
+
+ }
+
+ function invalidateRow(row) {
+ invalidateRows([row]);
+ }
+
+ function applyFormatResultToCellNode(formatterResult, cellNode, suppressRemove) {
+ if (typeof formatterResult === 'string') {
+ cellNode.innerHTML = formatterResult;
+ return;
+ }
+ cellNode.innerHTML = formatterResult.text;
+ if (formatterResult.removeClasses && !suppressRemove) {
+ cellNode.removeClass(formatterResult.removeClasses);
+ }
+ if (formatterResult.addClasses) {
+ cellNode.addClass(formatterResult.addClasses);
+ }
+ }
+
+ function updateCell(row, cell) {
+ var cellNode = getCellNode(row, cell);
+ if (!cellNode) {
+ return;
+ }
+
+ var m = columns[cell], d = getDataItem(row);
+ if (currentEditor && activeRow === row && activeCell === cell) {
+ currentEditor.loadValue(d);
+ } else {
+ var formatterResult = d ? getFormatter(row, m)(row, cell, getDataItemValueForColumn(d, m), m, d) : "";
+ applyFormatResultToCellNode(formatterResult, cellNode);
+ invalidatePostProcessingResults(row);
+ }
+ }
+
+ function updateRow(row) {
+ var cacheEntry = rowsCache[row];
+ if (!cacheEntry) {
+ return;
+ }
+
+ ensureCellNodesInRowsCache(row);
+
+ var formatterResult, d = getDataItem(row);
+
+ for (var columnIdx in cacheEntry.cellNodesByColumnIdx) {
+ if (!cacheEntry.cellNodesByColumnIdx.hasOwnProperty(columnIdx)) {
+ continue;
+ }
+
+ columnIdx = columnIdx | 0;
+ var m = columns[columnIdx],
+ node = cacheEntry.cellNodesByColumnIdx[columnIdx];
+
+ if (row === activeRow && columnIdx === activeCell && currentEditor) {
+ currentEditor.loadValue(d);
+ } else if (d) {
+ formatterResult = getFormatter(row, m)(row, columnIdx, getDataItemValueForColumn(d, m), m, d);
+ applyFormatResultToCellNode(formatterResult, node);
+ } else {
+ node.innerHTML = "";
+ }
+ }
+
+ invalidatePostProcessingResults(row);
+ }
+
+ function getViewportHeight() {
+ return parseFloat($.css($container[0], "height", true)) -
+ parseFloat($.css($container[0], "paddingTop", true)) -
+ parseFloat($.css($container[0], "paddingBottom", true)) -
+ parseFloat($.css($headerScroller[0], "height")) - getVBoxDelta($headerScroller) -
+ (options.showTopPanel ? options.topPanelHeight + getVBoxDelta($topPanelScroller) : 0) -
+ (options.showHeaderRow ? options.headerRowHeight + getVBoxDelta($headerRowScroller) : 0) -
+ (options.createFooterRow && options.showFooterRow ? options.footerRowHeight + getVBoxDelta($footerRowScroller) : 0);
+ }
+
+ function resizeCanvas() {
+ if (!initialized) { return; }
+ if (options.autoHeight) {
+ viewportH = options.rowHeight * getDataLengthIncludingAddNew();
+ } else {
+ viewportH = getViewportHeight();
+ }
+
+ numVisibleRows = Math.ceil(viewportH / options.rowHeight);
+ viewportW = parseFloat($.css($container[0], "width", true));
+ if (!options.autoHeight) {
+ $viewport.height(viewportH);
+ }
+
+ if (options.forceFitColumns) {
+ autosizeColumns();
+ }
+
+ updateRowCount();
+ handleScroll();
+ // Since the width has changed, force the render() to reevaluate virtually rendered cells.
+ lastRenderedScrollLeft = -1;
+ render();
+ }
+
+ function updatePagingStatusFromView( pagingInfo ) {
+ pagingActive = (pagingInfo.pageSize !== 0);
+ pagingIsLastPage = (pagingInfo.pageNum == pagingInfo.totalPages - 1);
+ }
+
+ function updateRowCount() {
+ if (!initialized) { return; }
+
+ var dataLength = getDataLength();
+ var dataLengthIncludingAddNew = getDataLengthIncludingAddNew();
+ var numberOfRows = dataLengthIncludingAddNew +
+ (options.leaveSpaceForNewRows ? numVisibleRows - 1 : 0);
+
+ var oldViewportHasVScroll = viewportHasVScroll;
+ // with autoHeight, we do not need to accommodate the vertical scroll bar
+ viewportHasVScroll = !options.autoHeight && (numberOfRows * options.rowHeight > viewportH);
+ viewportHasHScroll = (canvasWidth > viewportW - scrollbarDimensions.width);
+
+ makeActiveCellNormal();
+
+ // remove the rows that are now outside of the data range
+ // this helps avoid redundant calls to .removeRow() when the size of the data decreased by thousands of rows
+ var r1 = dataLength - 1;
+ for (var i in rowsCache) {
+ if (i > r1) {
+ removeRowFromCache(i);
+ }
+ }
+ if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
+
+ if (activeCellNode && activeRow > r1) {
+ resetActiveCell();
+ }
+
+ var oldH = h;
+ th = Math.max(options.rowHeight * numberOfRows, viewportH - scrollbarDimensions.height);
+ if (th < maxSupportedCssHeight) {
+ // just one page
+ h = ph = th;
+ n = 1;
+ cj = 0;
+ } else {
+ // break into pages
+ h = maxSupportedCssHeight;
+ ph = h / 100;
+ n = Math.floor(th / ph);
+ cj = (th - h) / (n - 1);
+ }
+
+ if (h !== oldH) {
+ $canvas.css("height", h);
+ scrollTop = $viewport[0].scrollTop;
+ }
+
+ var oldScrollTopInRange = (scrollTop + offset <= th - viewportH);
+
+ if (th == 0 || scrollTop == 0) {
+ page = offset = 0;
+ } else if (oldScrollTopInRange) {
+ // maintain virtual position
+ scrollTo(scrollTop + offset);
+ } else {
+ // scroll to bottom
+ scrollTo(th - viewportH);
+ }
+
+ if (h != oldH && options.autoHeight) {
+ resizeCanvas();
+ }
+
+ if (options.forceFitColumns && oldViewportHasVScroll != viewportHasVScroll) {
+ autosizeColumns();
+ }
+ updateCanvasWidth(false);
+ }
+
+ function getVisibleRange(viewportTop, viewportLeft) {
+ if (viewportTop == null) {
+ viewportTop = scrollTop;
+ }
+ if (viewportLeft == null) {
+ viewportLeft = scrollLeft;
+ }
+
+ return {
+ top: getRowFromPosition(viewportTop),
+ bottom: getRowFromPosition(viewportTop + viewportH) + 1,
+ leftPx: viewportLeft,
+ rightPx: viewportLeft + viewportW
+ };
+ }
+
+ function getRenderedRange(viewportTop, viewportLeft) {
+ var range = getVisibleRange(viewportTop, viewportLeft);
+ var buffer = Math.round(viewportH / options.rowHeight);
+ var minBuffer = 3;
+
+ if (vScrollDir == -1) {
+ range.top -= buffer;
+ range.bottom += minBuffer;
+ } else if (vScrollDir == 1) {
+ range.top -= minBuffer;
+ range.bottom += buffer;
+ } else {
+ range.top -= minBuffer;
+ range.bottom += minBuffer;
+ }
+
+ range.top = Math.max(0, range.top);
+ range.bottom = Math.min(getDataLengthIncludingAddNew() - 1, range.bottom);
+
+ range.leftPx -= viewportW;
+ range.rightPx += viewportW;
+
+ range.leftPx = Math.max(0, range.leftPx);
+ range.rightPx = Math.min(canvasWidth, range.rightPx);
+
+ return range;
+ }
+
+ function ensureCellNodesInRowsCache(row) {
+ var cacheEntry = rowsCache[row];
+ if (cacheEntry) {
+ if (cacheEntry.cellRenderQueue.length) {
+ var lastChild = cacheEntry.rowNode.lastChild;
+ while (cacheEntry.cellRenderQueue.length) {
+ var columnIdx = cacheEntry.cellRenderQueue.pop();
+ cacheEntry.cellNodesByColumnIdx[columnIdx] = lastChild;
+ lastChild = lastChild.previousSibling;
+ }
+ }
+ }
+ }
+
+ function cleanUpCells(range, row) {
+ var totalCellsRemoved = 0;
+ var cacheEntry = rowsCache[row];
+
+ // Remove cells outside the range.
+ var cellsToRemove = [];
+ for (var i in cacheEntry.cellNodesByColumnIdx) {
+ // I really hate it when people mess with Array.prototype.
+ if (!cacheEntry.cellNodesByColumnIdx.hasOwnProperty(i)) {
+ continue;
+ }
+
+ // This is a string, so it needs to be cast back to a number.
+ i = i | 0;
+
+ var colspan = cacheEntry.cellColSpans[i];
+ if (columnPosLeft[i] > range.rightPx ||
+ columnPosRight[Math.min(columns.length - 1, i + colspan - 1)] < range.leftPx) {
+ if (!(row == activeRow && i == activeCell)) {
+ cellsToRemove.push(i);
+ }
+ }
+ }
+
+ var cellToRemove, node;
+ postProcessgroupId++;
+ while ((cellToRemove = cellsToRemove.pop()) != null) {
+ node = cacheEntry.cellNodesByColumnIdx[cellToRemove];
+ if (options.enableAsyncPostRenderCleanup && postProcessedRows[row] && postProcessedRows[row][cellToRemove]) {
+ queuePostProcessedCellForCleanup(node, cellToRemove, row);
+ } else {
+ cacheEntry.rowNode.removeChild(node);
+ }
+
+ delete cacheEntry.cellColSpans[cellToRemove];
+ delete cacheEntry.cellNodesByColumnIdx[cellToRemove];
+ if (postProcessedRows[row]) {
+ delete postProcessedRows[row][cellToRemove];
+ }
+ totalCellsRemoved++;
+ }
+ }
+
+ function cleanUpAndRenderCells(range) {
+ var cacheEntry;
+ var stringArray = [];
+ var processedRows = [];
+ var cellsAdded;
+ var totalCellsAdded = 0;
+ var colspan;
+
+ for (var row = range.top, btm = range.bottom; row <= btm; row++) {
+ cacheEntry = rowsCache[row];
+ if (!cacheEntry) {
+ continue;
+ }
+
+ // cellRenderQueue populated in renderRows() needs to be cleared first
+ ensureCellNodesInRowsCache(row);
+
+ cleanUpCells(range, row);
+
+ // Render missing cells.
+ cellsAdded = 0;
+
+ var metadata = data.getItemMetadata && data.getItemMetadata(row);
+ metadata = metadata && metadata.columns;
+
+ var d = getDataItem(row);
+
+ // TODO: shorten this loop (index? heuristics? binary search?)
+ for (var i = 0, ii = columns.length; i < ii; i++) {
+ // Cells to the right are outside the range.
+ if (columnPosLeft[i] > range.rightPx) {
+ break;
+ }
+
+ // Already rendered.
+ if ((colspan = cacheEntry.cellColSpans[i]) != null) {
+ i += (colspan > 1 ? colspan - 1 : 0);
+ continue;
+ }
+
+ colspan = 1;
+ if (metadata) {
+ var columnData = metadata[columns[i].id] || metadata[i];
+ colspan = (columnData && columnData.colspan) || 1;
+ if (colspan === "*") {
+ colspan = ii - i;
+ }
+ }
+
+ if (columnPosRight[Math.min(ii - 1, i + colspan - 1)] > range.leftPx) {
+ appendCellHtml(stringArray, row, i, colspan, d);
+ cellsAdded++;
+ }
+
+ i += (colspan > 1 ? colspan - 1 : 0);
+ }
+
+ if (cellsAdded) {
+ totalCellsAdded += cellsAdded;
+ processedRows.push(row);
+ }
+ }
+
+ if (!stringArray.length) {
+ return;
+ }
+
+ var x = document.createElement("div");
+ x.innerHTML = stringArray.join("");
+
+ var processedRow;
+ var node;
+ while ((processedRow = processedRows.pop()) != null) {
+ cacheEntry = rowsCache[processedRow];
+ var columnIdx;
+ while ((columnIdx = cacheEntry.cellRenderQueue.pop()) != null) {
+ node = x.lastChild;
+ cacheEntry.rowNode.appendChild(node);
+ cacheEntry.cellNodesByColumnIdx[columnIdx] = node;
+ }
+ }
+ }
+
+ function renderRows(range) {
+ var parentNode = $canvas[0],
+ stringArray = [],
+ rows = [],
+ needToReselectCell = false,
+ dataLength = getDataLength();
+
+ for (var i = range.top, ii = range.bottom; i <= ii; i++) {
+ if (rowsCache[i]) {
+ continue;
+ }
+ renderedRows++;
+ rows.push(i);
+
+ // Create an entry right away so that appendRowHtml() can
+ // start populatating it.
+ rowsCache[i] = {
+ "rowNode": null,
+
+ // ColSpans of rendered cells (by column idx).
+ // Can also be used for checking whether a cell has been rendered.
+ "cellColSpans": [],
+
+ // Cell nodes (by column idx). Lazy-populated by ensureCellNodesInRowsCache().
+ "cellNodesByColumnIdx": [],
+
+ // Column indices of cell nodes that have been rendered, but not yet indexed in
+ // cellNodesByColumnIdx. These are in the same order as cell nodes added at the
+ // end of the row.
+ "cellRenderQueue": []
+ };
+
+ appendRowHtml(stringArray, i, range, dataLength);
+ if (activeCellNode && activeRow === i) {
+ needToReselectCell = true;
+ }
+ counter_rows_rendered++;
+ }
+
+ if (!rows.length) { return; }
+
+ var x = document.createElement("div");
+ x.innerHTML = stringArray.join("");
+
+ for (var i = 0, ii = rows.length; i < ii; i++) {
+ rowsCache[rows[i]].rowNode = parentNode.appendChild(x.firstChild);
+ }
+
+ if (needToReselectCell) {
+ activeCellNode = getCellNode(activeRow, activeCell);
+ }
+ }
+
+ function startPostProcessing() {
+ if (!options.enableAsyncPostRender) {
+ return;
+ }
+ clearTimeout(h_postrender);
+ h_postrender = setTimeout(asyncPostProcessRows, options.asyncPostRenderDelay);
+ }
+
+ function startPostProcessingCleanup() {
+ if (!options.enableAsyncPostRenderCleanup) {
+ return;
+ }
+ clearTimeout(h_postrenderCleanup);
+ h_postrenderCleanup = setTimeout(asyncPostProcessCleanupRows, options.asyncPostRenderCleanupDelay);
+ }
+
+ function invalidatePostProcessingResults(row) {
+ // change status of columns to be re-rendered
+ for (var columnIdx in postProcessedRows[row]) {
+ if (postProcessedRows[row].hasOwnProperty(columnIdx)) {
+ postProcessedRows[row][columnIdx] = 'C';
+ }
+ }
+ postProcessFromRow = Math.min(postProcessFromRow, row);
+ postProcessToRow = Math.max(postProcessToRow, row);
+ startPostProcessing();
+ }
+
+ function updateRowPositions() {
+ for (var row in rowsCache) {
+ rowsCache[row].rowNode.style.top = getRowTop(row) + "px";
+ }
+ }
+
+ function render() {
+ if (!initialized) { return; }
+ var visible = getVisibleRange();
+ var rendered = getRenderedRange();
+
+ // remove rows no longer in the viewport
+ cleanupRows(rendered);
+
+ // add new rows & missing cells in existing rows
+ if (lastRenderedScrollLeft != scrollLeft) {
+ cleanUpAndRenderCells(rendered);
+ }
+
+ // render missing rows
+ renderRows(rendered);
+
+ postProcessFromRow = visible.top;
+ postProcessToRow = Math.min(getDataLengthIncludingAddNew() - 1, visible.bottom);
+ startPostProcessing();
+
+ lastRenderedScrollTop = scrollTop;
+ lastRenderedScrollLeft = scrollLeft;
+ h_render = null;
+ }
+
+ function handleHeaderRowScroll() {
+ var scrollLeft = $headerRowScroller[0].scrollLeft;
+ if (scrollLeft != $viewport[0].scrollLeft) {
+ $viewport[0].scrollLeft = scrollLeft;
+ }
+ }
+
+ function handleFooterRowScroll() {
+ var scrollLeft = $footerRowScroller[0].scrollLeft;
+ if (scrollLeft != $viewport[0].scrollLeft) {
+ $viewport[0].scrollLeft = scrollLeft;
+ }
+ }
+
+ function handleScroll() {
+ scrollTop = $viewport[0].scrollTop;
+ scrollLeft = $viewport[0].scrollLeft;
+ var vScrollDist = Math.abs(scrollTop - prevScrollTop);
+ var hScrollDist = Math.abs(scrollLeft - prevScrollLeft);
+
+ if (hScrollDist) {
+ prevScrollLeft = scrollLeft;
+ $headerScroller[0].scrollLeft = scrollLeft;
+ $topPanelScroller[0].scrollLeft = scrollLeft;
+ $headerRowScroller[0].scrollLeft = scrollLeft;
+ if (options.createFooterRow) {
+ $footerRowScroller[0].scrollLeft = scrollLeft;
+ }
+ }
+
+ if (vScrollDist) {
+ vScrollDir = prevScrollTop < scrollTop ? 1 : -1;
+ prevScrollTop = scrollTop;
+
+ // switch virtual pages if needed
+ if (vScrollDist < viewportH) {
+ scrollTo(scrollTop + offset);
+ } else {
+ var oldOffset = offset;
+ if (h == viewportH) {
+ page = 0;
+ } else {
+ page = Math.min(n - 1, Math.floor(scrollTop * ((th - viewportH) / (h - viewportH)) * (1 / ph)));
+ }
+ offset = Math.round(page * cj);
+ if (oldOffset != offset) {
+ invalidateAllRows();
+ }
+ }
+ }
+
+ if (hScrollDist || vScrollDist) {
+ if (h_render) {
+ clearTimeout(h_render);
+ }
+
+ if (Math.abs(lastRenderedScrollTop - scrollTop) > 20 ||
+ Math.abs(lastRenderedScrollLeft - scrollLeft) > 20) {
+ if (options.forceSyncScrolling || (
+ Math.abs(lastRenderedScrollTop - scrollTop) < viewportH &&
+ Math.abs(lastRenderedScrollLeft - scrollLeft) < viewportW)) {
+ render();
+ } else {
+ h_render = setTimeout(render, 50);
+ }
+
+ trigger(self.onViewportChanged, {grid: self});
+ }
+ }
+
+ trigger(self.onScroll, {scrollLeft: scrollLeft, scrollTop: scrollTop, grid: self});
+ }
+
+ function asyncPostProcessRows() {
+ var dataLength = getDataLength();
+ while (postProcessFromRow <= postProcessToRow) {
+ var row = (vScrollDir >= 0) ? postProcessFromRow++ : postProcessToRow--;
+ var cacheEntry = rowsCache[row];
+ if (!cacheEntry || row >= dataLength) {
+ continue;
+ }
+
+ if (!postProcessedRows[row]) {
+ postProcessedRows[row] = {};
+ }
+
+ ensureCellNodesInRowsCache(row);
+ for (var columnIdx in cacheEntry.cellNodesByColumnIdx) {
+ if (!cacheEntry.cellNodesByColumnIdx.hasOwnProperty(columnIdx)) {
+ continue;
+ }
+
+ columnIdx = columnIdx | 0;
+
+ var m = columns[columnIdx];
+ var processedStatus = postProcessedRows[row][columnIdx]; // C=cleanup and re-render, R=rendered
+ if (m.asyncPostRender && processedStatus !== 'R') {
+ var node = cacheEntry.cellNodesByColumnIdx[columnIdx];
+ if (node) {
+ m.asyncPostRender(node, row, getDataItem(row), m, (processedStatus === 'C'));
+ }
+ postProcessedRows[row][columnIdx] = 'R';
+ }
+ }
+
+ h_postrender = setTimeout(asyncPostProcessRows, options.asyncPostRenderDelay);
+ return;
+ }
+ }
+
+ function asyncPostProcessCleanupRows() {
+ if (postProcessedCleanupQueue.length > 0) {
+ var groupId = postProcessedCleanupQueue[0].groupId;
+
+ // loop through all queue members with this groupID
+ while (postProcessedCleanupQueue.length > 0 && postProcessedCleanupQueue[0].groupId == groupId) {
+ var entry = postProcessedCleanupQueue.shift();
+ if (entry.actionType == 'R') {
+ $(entry.node).remove();
+ }
+ if (entry.actionType == 'C') {
+ var column = columns[entry.columnIdx];
+ if (column.asyncPostRenderCleanup && entry.node) {
+ // cleanup must also remove element
+ column.asyncPostRenderCleanup(entry.node, entry.rowIdx, column);
+ }
+ }
+ }
+
+ // call this function again after the specified delay
+ h_postrenderCleanup = setTimeout(asyncPostProcessCleanupRows, options.asyncPostRenderCleanupDelay);
+ }
+ }
+
+ function updateCellCssStylesOnRenderedRows(addedHash, removedHash) {
+ var node, columnId, addedRowHash, removedRowHash;
+ for (var row in rowsCache) {
+ removedRowHash = removedHash && removedHash[row];
+ addedRowHash = addedHash && addedHash[row];
+
+ if (removedRowHash) {
+ for (columnId in removedRowHash) {
+ if (!addedRowHash || removedRowHash[columnId] != addedRowHash[columnId]) {
+ node = getCellNode(row, getColumnIndex(columnId));
+ if (node) {
+ $(node).removeClass(removedRowHash[columnId]);
+ }
+ }
+ }
+ }
+
+ if (addedRowHash) {
+ for (columnId in addedRowHash) {
+ if (!removedRowHash || removedRowHash[columnId] != addedRowHash[columnId]) {
+ node = getCellNode(row, getColumnIndex(columnId));
+ if (node) {
+ $(node).addClass(addedRowHash[columnId]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ function addCellCssStyles(key, hash) {
+ if (cellCssClasses[key]) {
+ throw new Error("addCellCssStyles: cell CSS hash with key '" + key + "' already exists.");
+ }
+
+ cellCssClasses[key] = hash;
+ updateCellCssStylesOnRenderedRows(hash, null);
+
+ trigger(self.onCellCssStylesChanged, { "key": key, "hash": hash, "grid": self });
+ }
+
+ function removeCellCssStyles(key) {
+ if (!cellCssClasses[key]) {
+ return;
+ }
+
+ updateCellCssStylesOnRenderedRows(null, cellCssClasses[key]);
+ delete cellCssClasses[key];
+
+ trigger(self.onCellCssStylesChanged, { "key": key, "hash": null, "grid": self });
+ }
+
+ function setCellCssStyles(key, hash) {
+ var prevHash = cellCssClasses[key];
+
+ cellCssClasses[key] = hash;
+ updateCellCssStylesOnRenderedRows(hash, prevHash);
+
+ trigger(self.onCellCssStylesChanged, { "key": key, "hash": hash, "grid": self });
+ }
+
+ function getCellCssStyles(key) {
+ return cellCssClasses[key];
+ }
+
+ function flashCell(row, cell, speed) {
+ speed = speed || 100;
+ if (rowsCache[row]) {
+ var $cell = $(getCellNode(row, cell));
+
+ function toggleCellClass(times) {
+ if (!times) {
+ return;
+ }
+ setTimeout(function () {
+ $cell.queue(function () {
+ $cell.toggleClass(options.cellFlashingCssClass).dequeue();
+ toggleCellClass(times - 1);
+ });
+ },
+ speed);
+ }
+
+ toggleCellClass(4);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Interactivity
+
+ function handleMouseWheel(e) {
+ var rowNode = $(e.target).closest(".slick-row")[0];
+ if (rowNode != rowNodeFromLastMouseWheelEvent) {
+ if (zombieRowNodeFromLastMouseWheelEvent && zombieRowNodeFromLastMouseWheelEvent != rowNode) {
+ if (options.enableAsyncPostRenderCleanup && zombieRowPostProcessedFromLastMouseWheelEvent) {
+ queuePostProcessedRowForCleanup(zombieRowCacheFromLastMouseWheelEvent,
+ zombieRowPostProcessedFromLastMouseWheelEvent);
+ } else {
+ $canvas[0].removeChild(zombieRowNodeFromLastMouseWheelEvent);
+ }
+ zombieRowNodeFromLastMouseWheelEvent = null;
+ zombieRowCacheFromLastMouseWheelEvent = null;
+ zombieRowPostProcessedFromLastMouseWheelEvent = null;
+
+ if (options.enableAsyncPostRenderCleanup) { startPostProcessingCleanup(); }
+ }
+ rowNodeFromLastMouseWheelEvent = rowNode;
+ }
+ }
+
+ function handleDragInit(e, dd) {
+ var cell = getCellFromEvent(e);
+ if (!cell || !cellExists(cell.row, cell.cell)) {
+ return false;
+ }
+
+ var retval = trigger(self.onDragInit, dd, e);
+ if (e.isImmediatePropagationStopped()) {
+ return retval;
+ }
+
+ // if nobody claims to be handling drag'n'drop by stopping immediate propagation,
+ // cancel out of it
+ return false;
+ }
+
+ function handleDragStart(e, dd) {
+ var cell = getCellFromEvent(e);
+ if (!cell || !cellExists(cell.row, cell.cell)) {
+ return false;
+ }
+
+ var retval = trigger(self.onDragStart, dd, e);
+ if (e.isImmediatePropagationStopped()) {
+ return retval;
+ }
+
+ return false;
+ }
+
+ function handleDrag(e, dd) {
+ return trigger(self.onDrag, dd, e);
+ }
+
+ function handleDragEnd(e, dd) {
+ trigger(self.onDragEnd, dd, e);
+ }
+
+ function handleKeyDown(e) {
+ trigger(self.onKeyDown, {row: activeRow, cell: activeCell, grid: self}, e);
+ var handled = e.isImmediatePropagationStopped();
+ var keyCode = Slick.keyCode;
+
+ if (!handled) {
+ if (!e.shiftKey && !e.altKey && !e.ctrlKey) {
+ // editor may specify an array of keys to bubble
+ if (options.editable && currentEditor && currentEditor.keyCaptureList) {
+ if (currentEditor.keyCaptureList.indexOf( e.which ) > -1) {
+ return;
+ }
+ }
+ if (e.which == keyCode.ESCAPE) {
+ if (!getEditorLock().isActive()) {
+ return; // no editing mode to cancel, allow bubbling and default processing (exit without cancelling the event)
+ }
+ cancelEditAndSetFocus();
+ } else if (e.which == keyCode.PAGE_DOWN) {
+ navigatePageDown();
+ handled = true;
+ } else if (e.which == keyCode.PAGE_UP) {
+ navigatePageUp();
+ handled = true;
+ } else if (e.which == keyCode.LEFT) {
+ handled = navigateLeft();
+ } else if (e.which == keyCode.RIGHT) {
+ handled = navigateRight();
+ } else if (e.which == keyCode.UP) {
+ handled = navigateUp();
+ } else if (e.which == keyCode.DOWN) {
+ handled = navigateDown();
+ } else if (e.which == keyCode.TAB) {
+ handled = navigateNext();
+ } else if (e.which == keyCode.ENTER) {
+ if (options.editable) {
+ if (currentEditor) {
+ // adding new row
+ if (activeRow === getDataLength()) {
+ navigateDown();
+ } else {
+ commitEditAndSetFocus();
+ }
+ } else {
+ if (getEditorLock().commitCurrentEdit()) {
+ makeActiveCellEditable();
+ }
+ }
+ }
+ handled = true;
+ }
+ } else if (e.which == keyCode.TAB && e.shiftKey && !e.ctrlKey && !e.altKey) {
+ handled = navigatePrev();
+ }
+ }
+
+ if (handled) {
+ // the event has been handled so don't let parent element (bubbling/propagation) or browser (default) handle it
+ e.stopPropagation();
+ e.preventDefault();
+ try {
+ e.originalEvent.keyCode = 0; // prevent default behaviour for special keys in IE browsers (F3, F5, etc.)
+ }
+ // ignore exceptions - setting the original event's keycode throws access denied exception for "Ctrl"
+ // (hitting control key only, nothing else), "Shift" (maybe others)
+ catch (error) {
+ }
+ }
+ }
+
+ function handleClick(e) {
+ if (!currentEditor) {
+ // if this click resulted in some cell child node getting focus,
+ // don't steal it back - keyboard events will still bubble up
+ // IE9+ seems to default DIVs to tabIndex=0 instead of -1, so check for cell clicks directly.
+ if (e.target != document.activeElement || $(e.target).hasClass("slick-cell")) {
+ setFocus();
+ }
+ }
+
+ var cell = getCellFromEvent(e);
+ if (!cell || (currentEditor !== null && activeRow == cell.row && activeCell == cell.cell)) {
+ return;
+ }
+
+ trigger(self.onClick, {row: cell.row, cell: cell.cell, grid: self}, e);
+ if (e.isImmediatePropagationStopped()) {
+ return;
+ }
+
+ // this optimisation causes trouble - MLeibman #329
+ //if ((activeCell != cell.cell || activeRow != cell.row) && canCellBeActive(cell.row, cell.cell)) {
+ if (canCellBeActive(cell.row, cell.cell)) {
+ if (!getEditorLock().isActive() || getEditorLock().commitCurrentEdit()) {
+ scrollRowIntoView(cell.row, false);
+
+ var preClickModeOn = (e.target && e.target.className === Slick.preClickClassName);
+ setActiveCellInternal(getCellNode(cell.row, cell.cell), null, preClickModeOn);
+ }
+ }
+ }
+
+ function handleContextMenu(e) {
+ var $cell = $(e.target).closest(".slick-cell", $canvas);
+ if ($cell.length === 0) {
+ return;
+ }
+
+ // are we editing this cell?
+ if (activeCellNode === $cell[0] && currentEditor !== null) {
+ return;
+ }
+
+ trigger(self.onContextMenu, {grid: self}, e);
+ }
+
+ function handleDblClick(e) {
+ var cell = getCellFromEvent(e);
+ if (!cell || (currentEditor !== null && activeRow == cell.row && activeCell == cell.cell)) {
+ return;
+ }
+
+ trigger(self.onDblClick, {row: cell.row, cell: cell.cell, grid: self}, e);
+ if (e.isImmediatePropagationStopped()) {
+ return;
+ }
+
+ if (options.editable) {
+ gotoCell(cell.row, cell.cell, true);
+ }
+ }
+
+ function handleHeaderMouseEnter(e) {
+ trigger(self.onHeaderMouseEnter, {
+ "column": $(this).data("column"),
+ "grid": self
+ }, e);
+ }
+
+ function handleHeaderMouseLeave(e) {
+ trigger(self.onHeaderMouseLeave, {
+ "column": $(this).data("column"),
+ "grid": self
+ }, e);
+ }
+
+ function handleHeaderContextMenu(e) {
+ var $header = $(e.target).closest(".slick-header-column", ".slick-header-columns");
+ var column = $header && $header.data("column");
+ trigger(self.onHeaderContextMenu, {column: column, grid: self}, e);
+ }
+
+ function handleHeaderClick(e) {
+ var $header = $(e.target).closest(".slick-header-column", ".slick-header-columns");
+ var column = $header && $header.data("column");
+ if (column) {
+ trigger(self.onHeaderClick, {column: column, grid: self}, e);
+ }
+ }
+
+ function handleMouseEnter(e) {
+ trigger(self.onMouseEnter, {grid: self}, e);
+ }
+
+ function handleMouseLeave(e) {
+ trigger(self.onMouseLeave, {grid: self}, e);
+ }
+
+ function cellExists(row, cell) {
+ return !(row < 0 || row >= getDataLength() || cell < 0 || cell >= columns.length);
+ }
+
+ function getCellFromPoint(x, y) {
+ var row = getRowFromPosition(y);
+ var cell = 0;
+
+ var w = 0;
+ for (var i = 0; i < columns.length && w < x; i++) {
+ w += columns[i].width;
+ cell++;
+ }
+
+ if (cell < 0) {
+ cell = 0;
+ }
+
+ return {row: row, cell: cell - 1};
+ }
+
+ function getCellFromNode(cellNode) {
+ // read column number from .l<columnNumber> CSS class
+ var cls = /l\d+/.exec(cellNode.className);
+ if (!cls) {
+ throw new Error("getCellFromNode: cannot get cell - " + cellNode.className);
+ }
+ return parseInt(cls[0].substr(1, cls[0].length - 1), 10);
+ }
+
+ function getRowFromNode(rowNode) {
+ for (var row in rowsCache) {
+ if (rowsCache[row].rowNode === rowNode) {
+ return row | 0;
+ }
+ }
+
+ return null;
+ }
+
+ function getCellFromEvent(e) {
+ var $cell = $(e.target).closest(".slick-cell", $canvas);
+ if (!$cell.length) {
+ return null;
+ }
+
+ var row = getRowFromNode($cell[0].parentNode);
+ var cell = getCellFromNode($cell[0]);
+
+ if (row == null || cell == null) {
+ return null;
+ } else {
+ return {
+ "row": row,
+ "cell": cell
+ };
+ }
+ }
+
+ function getCellNodeBox(row, cell) {
+ if (!cellExists(row, cell)) {
+ return null;
+ }
+
+ var y1 = getRowTop(row);
+ var y2 = y1 + options.rowHeight - 1;
+ var x1 = 0;
+ for (var i = 0; i < cell; i++) {
+ x1 += columns[i].width;
+ }
+ var x2 = x1 + columns[cell].width;
+
+ return {
+ top: y1,
+ left: x1,
+ bottom: y2,
+ right: x2
+ };
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Cell switching
+
+ function resetActiveCell() {
+ setActiveCellInternal(null, false);
+ }
+
+ function setFocus() {
+ if (tabbingDirection == -1) {
+ $focusSink[0].focus();
+ } else {
+ $focusSink2[0].focus();
+ }
+ }
+
+ function scrollCellIntoView(row, cell, doPaging) {
+ scrollRowIntoView(row, doPaging);
+
+ var colspan = getColspan(row, cell);
+ var left = columnPosLeft[cell],
+ right = columnPosRight[cell + (colspan > 1 ? colspan - 1 : 0)],
+ scrollRight = scrollLeft + viewportW;
+
+ if (left < scrollLeft) {
+ $viewport.scrollLeft(left);
+ handleScroll();
+ render();
+ } else if (right > scrollRight) {
+ $viewport.scrollLeft(Math.min(left, right - $viewport[0].clientWidth));
+ handleScroll();
+ render();
+ }
+ }
+
+ function setActiveCellInternal(newCell, opt_editMode, preClickModeOn) {
+ if (activeCellNode !== null) {
+ makeActiveCellNormal();
+ $(activeCellNode).removeClass("active");
+ if (rowsCache[activeRow]) {
+ $(rowsCache[activeRow].rowNode).removeClass("active");
+ }
+ }
+
+ var activeCellChanged = (activeCellNode !== newCell);
+ activeCellNode = newCell;
+
+ if (activeCellNode != null) {
+ activeRow = getRowFromNode(activeCellNode.parentNode);
+ activeCell = activePosX = getCellFromNode(activeCellNode);
+
+ if (opt_editMode == null) {
+ opt_editMode = (activeRow == getDataLength()) || options.autoEdit;
+ }
+
+ if (options.showCellSelection) {
+ $(activeCellNode).addClass("active");
+ $(rowsCache[activeRow].rowNode).addClass("active");
+ }
+
+ if (options.editable && opt_editMode && isCellPotentiallyEditable(activeRow, activeCell)) {
+ clearTimeout(h_editorLoader);
+
+ if (options.asyncEditorLoading) {
+ h_editorLoader = setTimeout(function () {
+ makeActiveCellEditable(undefined, preClickModeOn);
+ }, options.asyncEditorLoadDelay);
+ } else {
+ makeActiveCellEditable(undefined, preClickModeOn);
+ }
+ }
+ } else {
+ activeRow = activeCell = null;
+ }
+
+ // this optimisation causes trouble - MLeibman #329
+ //if (activeCellChanged) {
+ trigger(self.onActiveCellChanged, getActiveCell());
+ //}
+ }
+
+ function clearTextSelection() {
+ if (document.selection && document.selection.empty) {
+ try {
+ //IE fails here if selected element is not in dom
+ document.selection.empty();
+ } catch (e) { }
+ } else if (window.getSelection) {
+ var sel = window.getSelection();
+ if (sel && sel.removeAllRanges) {
+ sel.removeAllRanges();
+ }
+ }
+ }
+
+ function isCellPotentiallyEditable(row, cell) {
+ var dataLength = getDataLength();
+ // is the data for this row loaded?
+ if (row < dataLength && !getDataItem(row)) {
+ return false;
+ }
+
+ // are we in the Add New row? can we create new from this cell?
+ if (columns[cell].cannotTriggerInsert && row >= dataLength) {
+ return false;
+ }
+
+ // does this cell have an editor?
+ if (!getEditor(row, cell)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ function makeActiveCellNormal() {
+ if (!currentEditor) {
+ return;
+ }
+ trigger(self.onBeforeCellEditorDestroy, {editor: currentEditor, grid: self});
+ currentEditor.destroy();
+ currentEditor = null;
+
+ if (activeCellNode) {
+ var d = getDataItem(activeRow);
+ $(activeCellNode).removeClass("editable invalid");
+ if (d) {
+ var column = columns[activeCell];
+ var formatter = getFormatter(activeRow, column);
+ var formatterResult = formatter(activeRow, activeCell, getDataItemValueForColumn(d, column), column, d, self);
+ applyFormatResultToCellNode(formatterResult, activeCellNode);
+ invalidatePostProcessingResults(activeRow);
+ }
+ }
+
+ // if there previously was text selected on a page (such as selected text in the edit cell just removed),
+ // IE can't set focus to anything else correctly
+ if (navigator.userAgent.toLowerCase().match(/msie/)) {
+ clearTextSelection();
+ }
+
+ getEditorLock().deactivate(editController);
+ }
+
+ function makeActiveCellEditable(editor, preClickModeOn) {
+ if (!activeCellNode) {
+ return;
+ }
+ if (!options.editable) {
+ throw new Error("Grid : makeActiveCellEditable : should never get called when options.editable is false");
+ }
+
+ // cancel pending async call if there is one
+ clearTimeout(h_editorLoader);
+
+ if (!isCellPotentiallyEditable(activeRow, activeCell)) {
+ return;
+ }
+
+ var columnDef = columns[activeCell];
+ var item = getDataItem(activeRow);
+
+ if (trigger(self.onBeforeEditCell, {row: activeRow, cell: activeCell, item: item, column: columnDef, grid: self}) === false) {
+ setFocus();
+ return;
+ }
+
+ getEditorLock().activate(editController);
+ $(activeCellNode).addClass("editable");
+
+ var useEditor = editor || getEditor(activeRow, activeCell);
+
+ // don't clear the cell if a custom editor is passed through
+ if (!editor && !useEditor.suppressClearOnEdit) {
+ activeCellNode.innerHTML = "";
+ }
+
+ currentEditor = new useEditor({
+ grid: self,
+ gridPosition: absBox($container[0]),
+ position: absBox(activeCellNode),
+ container: activeCellNode,
+ column: columnDef,
+ item: item || {},
+ commitChanges: commitEditAndSetFocus,
+ cancelChanges: cancelEditAndSetFocus
+ });
+
+ if (item) {
+ currentEditor.loadValue(item);
+ if (preClickModeOn && currentEditor.preClick) {
+ currentEditor.preClick();
+ }
+ }
+
+ serializedEditorValue = currentEditor.serializeValue();
+
+ if (currentEditor.position) {
+ handleActiveCellPositionChange();
+ }
+ }
+
+ function commitEditAndSetFocus() {
+ // if the commit fails, it would do so due to a validation error
+ // if so, do not steal the focus from the editor
+ if (getEditorLock().commitCurrentEdit()) {
+ setFocus();
+ if (options.autoEdit) {
+ navigateDown();
+ }
+ }
+ }
+
+ function cancelEditAndSetFocus() {
+ if (getEditorLock().cancelCurrentEdit()) {
+ setFocus();
+ }
+ }
+
+ function absBox(elem) {
+ var box = {
+ top: elem.offsetTop,
+ left: elem.offsetLeft,
+ bottom: 0,
+ right: 0,
+ width: $(elem).outerWidth(),
+ height: $(elem).outerHeight(),
+ visible: true};
+ box.bottom = box.top + box.height;
+ box.right = box.left + box.width;
+
+ // walk up the tree
+ var offsetParent = elem.offsetParent;
+ while ((elem = elem.parentNode) != document.body) {
+ if (elem == null) break;
+
+ if (box.visible && elem.scrollHeight != elem.offsetHeight && $(elem).css("overflowY") != "visible") {
+ box.visible = box.bottom > elem.scrollTop && box.top < elem.scrollTop + elem.clientHeight;
+ }
+
+ if (box.visible && elem.scrollWidth != elem.offsetWidth && $(elem).css("overflowX") != "visible") {
+ box.visible = box.right > elem.scrollLeft && box.left < elem.scrollLeft + elem.clientWidth;
+ }
+
+ box.left -= elem.scrollLeft;
+ box.top -= elem.scrollTop;
+
+ if (elem === offsetParent) {
+ box.left += elem.offsetLeft;
+ box.top += elem.offsetTop;
+ offsetParent = elem.offsetParent;
+ }
+
+ box.bottom = box.top + box.height;
+ box.right = box.left + box.width;
+ }
+
+ return box;
+ }
+
+ function getActiveCellPosition() {
+ return absBox(activeCellNode);
+ }
+
+ function getGridPosition() {
+ return absBox($container[0])
+ }
+
+ function handleActiveCellPositionChange() {
+ if (!activeCellNode) {
+ return;
+ }
+
+ trigger(self.onActiveCellPositionChanged, {grid: self});
+
+ if (currentEditor) {
+ var cellBox = getActiveCellPosition();
+ if (currentEditor.show && currentEditor.hide) {
+ if (!cellBox.visible) {
+ currentEditor.hide();
+ } else {
+ currentEditor.show();
+ }
+ }
+
+ if (currentEditor.position) {
+ currentEditor.position(cellBox);
+ }
+ }
+ }
+
+ function getCellEditor() {
+ return currentEditor;
+ }
+
+ function getActiveCell() {
+ if (!activeCellNode) {
+ return null;
+ } else {
+ return {row: activeRow, cell: activeCell, grid: self};
+ }
+ }
+
+ function getActiveCellNode() {
+ return activeCellNode;
+ }
+
+ function scrollRowIntoView(row, doPaging) {
+ var rowAtTop = row * options.rowHeight;
+ var rowAtBottom = (row + 1) * options.rowHeight - viewportH + (viewportHasHScroll ? scrollbarDimensions.height : 0);
+
+ // need to page down?
+ if ((row + 1) * options.rowHeight > scrollTop + viewportH + offset) {
+ scrollTo(doPaging ? rowAtTop : rowAtBottom);
+ render();
+ }
+ // or page up?
+ else if (row * options.rowHeight < scrollTop + offset) {
+ scrollTo(doPaging ? rowAtBottom : rowAtTop);
+ render();
+ }
+ }
+
+ function scrollRowToTop(row) {
+ scrollTo(row * options.rowHeight);
+ render();
+ }
+
+ function scrollPage(dir) {
+ var deltaRows = dir * numVisibleRows;
+ scrollTo((getRowFromPosition(scrollTop) + deltaRows) * options.rowHeight);
+ render();
+
+ if (options.enableCellNavigation && activeRow != null) {
+ var row = activeRow + deltaRows;
+ var dataLengthIncludingAddNew = getDataLengthIncludingAddNew();
+ if (row >= dataLengthIncludingAddNew) {
+ row = dataLengthIncludingAddNew - 1;
+ }
+ if (row < 0) {
+ row = 0;
+ }
+
+ var cell = 0, prevCell = null;
+ var prevActivePosX = activePosX;
+ while (cell <= activePosX) {
+ if (canCellBeActive(row, cell)) {
+ prevCell = cell;
+ }
+ cell += getColspan(row, cell);
+ }
+
+ if (prevCell !== null) {
+ setActiveCellInternal(getCellNode(row, prevCell));
+ activePosX = prevActivePosX;
+ } else {
+ resetActiveCell();
+ }
+ }
+ }
+
+ function navigatePageDown() {
+ scrollPage(1);
+ }
+
+ function navigatePageUp() {
+ scrollPage(-1);
+ }
+
+ function getColspan(row, cell) {
+ var metadata = data.getItemMetadata && data.getItemMetadata(row);
+ if (!metadata || !metadata.columns) {
+ return 1;
+ }
+
+ var columnData = metadata.columns[columns[cell].id] || metadata.columns[cell];
+ var colspan = (columnData && columnData.colspan);
+ if (colspan === "*") {
+ colspan = columns.length - cell;
+ } else {
+ colspan = colspan || 1;
+ }
+
+ return colspan;
+ }
+
+ function findFirstFocusableCell(row) {
+ var cell = 0;
+ while (cell < columns.length) {
+ if (canCellBeActive(row, cell)) {
+ return cell;
+ }
+ cell += getColspan(row, cell);
+ }
+ return null;
+ }
+
+ function findLastFocusableCell(row) {
+ var cell = 0;
+ var lastFocusableCell = null;
+ while (cell < columns.length) {
+ if (canCellBeActive(row, cell)) {
+ lastFocusableCell = cell;
+ }
+ cell += getColspan(row, cell);
+ }
+ return lastFocusableCell;
+ }
+
+ function gotoRight(row, cell, posX) {
+ if (cell >= columns.length) {
+ return null;
+ }
+
+ do {
+ cell += getColspan(row, cell);
+ }
+ while (cell < columns.length && !canCellBeActive(row, cell));
+
+ if (cell < columns.length) {
+ return {
+ "row": row,
+ "cell": cell,
+ "posX": cell
+ };
+ }
+ return null;
+ }
+
+ function gotoLeft(row, cell, posX) {
+ if (cell <= 0) {
+ return null;
+ }
+
+ var firstFocusableCell = findFirstFocusableCell(row);
+ if (firstFocusableCell === null || firstFocusableCell >= cell) {
+ return null;
+ }
+
+ var prev = {
+ "row": row,
+ "cell": firstFocusableCell,
+ "posX": firstFocusableCell
+ };
+ var pos;
+ while (true) {
+ pos = gotoRight(prev.row, prev.cell, prev.posX);
+ if (!pos) {
+ return null;
+ }
+ if (pos.cell >= cell) {
+ return prev;
+ }
+ prev = pos;
+ }
+ }
+
+ function gotoDown(row, cell, posX) {
+ var prevCell;
+ var dataLengthIncludingAddNew = getDataLengthIncludingAddNew();
+ while (true) {
+ if (++row >= dataLengthIncludingAddNew) {
+ return null;
+ }
+
+ prevCell = cell = 0;
+ while (cell <= posX) {
+ prevCell = cell;
+ cell += getColspan(row, cell);
+ }
+
+ if (canCellBeActive(row, prevCell)) {
+ return {
+ "row": row,
+ "cell": prevCell,
+ "posX": posX
+ };
+ }
+ }
+ }
+
+ function gotoUp(row, cell, posX) {
+ var prevCell;
+ while (true) {
+ if (--row < 0) {
+ return null;
+ }
+
+ prevCell = cell = 0;
+ while (cell <= posX) {
+ prevCell = cell;
+ cell += getColspan(row, cell);
+ }
+
+ if (canCellBeActive(row, prevCell)) {
+ return {
+ "row": row,
+ "cell": prevCell,
+ "posX": posX
+ };
+ }
+ }
+ }
+
+ function gotoNext(row, cell, posX) {
+ if (row == null && cell == null) {
+ row = cell = posX = 0;
+ if (canCellBeActive(row, cell)) {
+ return {
+ "row": row,
+ "cell": cell,
+ "posX": cell
+ };
+ }
+ }
+
+ var pos = gotoRight(row, cell, posX);
+ if (pos) {
+ return pos;
+ }
+
+ var firstFocusableCell = null;
+ var dataLengthIncludingAddNew = getDataLengthIncludingAddNew();
+ while (++row < dataLengthIncludingAddNew) {
+ firstFocusableCell = findFirstFocusableCell(row);
+ if (firstFocusableCell !== null) {
+ return {
+ "row": row,
+ "cell": firstFocusableCell,
+ "posX": firstFocusableCell
+ };
+ }
+ }
+ return null;
+ }
+
+ function gotoPrev(row, cell, posX) {
+ if (row == null && cell == null) {
+ row = getDataLengthIncludingAddNew() - 1;
+ cell = posX = columns.length - 1;
+ if (canCellBeActive(row, cell)) {
+ return {
+ "row": row,
+ "cell": cell,
+ "posX": cell
+ };
+ }
+ }
+
+ var pos;
+ var lastSelectableCell;
+ while (!pos) {
+ pos = gotoLeft(row, cell, posX);
+ if (pos) {
+ break;
+ }
+ if (--row < 0) {
+ return null;
+ }
+
+ cell = 0;
+ lastSelectableCell = findLastFocusableCell(row);
+ if (lastSelectableCell !== null) {
+ pos = {
+ "row": row,
+ "cell": lastSelectableCell,
+ "posX": lastSelectableCell
+ };
+ }
+ }
+ return pos;
+ }
+
+ function navigateRight() {
+ return navigate("right");
+ }
+
+ function navigateLeft() {
+ return navigate("left");
+ }
+
+ function navigateDown() {
+ return navigate("down");
+ }
+
+ function navigateUp() {
+ return navigate("up");
+ }
+
+ function navigateNext() {
+ return navigate("next");
+ }
+
+ function navigatePrev() {
+ return navigate("prev");
+ }
+
+ /**
+ * @param {string} dir Navigation direction.
+ * @return {boolean} Whether navigation resulted in a change of active cell.
+ */
+ function navigate(dir) {
+ if (!options.enableCellNavigation) {
+ return false;
+ }
+
+ if (!activeCellNode && dir != "prev" && dir != "next") {
+ return false;
+ }
+
+ if (!getEditorLock().commitCurrentEdit()) {
+ return true;
+ }
+ setFocus();
+
+ var tabbingDirections = {
+ "up": -1,
+ "down": 1,
+ "left": -1,
+ "right": 1,
+ "prev": -1,
+ "next": 1
+ };
+ tabbingDirection = tabbingDirections[dir];
+
+ var stepFunctions = {
+ "up": gotoUp,
+ "down": gotoDown,
+ "left": gotoLeft,
+ "right": gotoRight,
+ "prev": gotoPrev,
+ "next": gotoNext
+ };
+ var stepFn = stepFunctions[dir];
+ var pos = stepFn(activeRow, activeCell, activePosX);
+ if (pos) {
+ var isAddNewRow = (pos.row == getDataLength());
+ scrollCellIntoView(pos.row, pos.cell, !isAddNewRow);
+ setActiveCellInternal(getCellNode(pos.row, pos.cell));
+ activePosX = pos.posX;
+ return true;
+ } else {
+ setActiveCellInternal(getCellNode(activeRow, activeCell));
+ return false;
+ }
+ }
+
+ function getCellNode(row, cell) {
+ if (rowsCache[row]) {
+ ensureCellNodesInRowsCache(row);
+ return rowsCache[row].cellNodesByColumnIdx[cell];
+ }
+ return null;
+ }
+
+ function setActiveCell(row, cell) {
+ if (!initialized) { return; }
+ if (row > getDataLength() || row < 0 || cell >= columns.length || cell < 0) {
+ return;
+ }
+
+ if (!options.enableCellNavigation) {
+ return;
+ }
+
+ scrollCellIntoView(row, cell, false);
+ setActiveCellInternal(getCellNode(row, cell), false);
+ }
+
+ function canCellBeActive(row, cell) {
+ if (!options.enableCellNavigation || row >= getDataLengthIncludingAddNew() ||
+ row < 0 || cell >= columns.length || cell < 0) {
+ return false;
+ }
+
+ var rowMetadata = data.getItemMetadata && data.getItemMetadata(row);
+ if (rowMetadata && typeof rowMetadata.focusable === "boolean") {
+ return rowMetadata.focusable;
+ }
+
+ var columnMetadata = rowMetadata && rowMetadata.columns;
+ if (columnMetadata && columnMetadata[columns[cell].id] && typeof columnMetadata[columns[cell].id].focusable === "boolean") {
+ return columnMetadata[columns[cell].id].focusable;
+ }
+ if (columnMetadata && columnMetadata[cell] && typeof columnMetadata[cell].focusable === "boolean") {
+ return columnMetadata[cell].focusable;
+ }
+
+ return columns[cell].focusable;
+ }
+
+ function canCellBeSelected(row, cell) {
+ if (row >= getDataLength() || row < 0 || cell >= columns.length || cell < 0) {
+ return false;
+ }
+
+ var rowMetadata = data.getItemMetadata && data.getItemMetadata(row);
+ if (rowMetadata && typeof rowMetadata.selectable === "boolean") {
+ return rowMetadata.selectable;
+ }
+
+ var columnMetadata = rowMetadata && rowMetadata.columns && (rowMetadata.columns[columns[cell].id] || rowMetadata.columns[cell]);
+ if (columnMetadata && typeof columnMetadata.selectable === "boolean") {
+ return columnMetadata.selectable;
+ }
+
+ return columns[cell].selectable;
+ }
+
+ function gotoCell(row, cell, forceEdit) {
+ if (!initialized) { return; }
+ if (!canCellBeActive(row, cell)) {
+ return;
+ }
+
+ if (!getEditorLock().commitCurrentEdit()) {
+ return;
+ }
+
+ scrollCellIntoView(row, cell, false);
+
+ var newCell = getCellNode(row, cell);
+
+ // if selecting the 'add new' row, start editing right away
+ setActiveCellInternal(newCell, forceEdit || (row === getDataLength()) || options.autoEdit);
+
+ // if no editor was created, set the focus back on the grid
+ if (!currentEditor) {
+ setFocus();
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // IEditor implementation for the editor lock
+
+ function commitCurrentEdit() {
+ var item = getDataItem(activeRow);
+ var column = columns[activeCell];
+
+ if (currentEditor) {
+ if (currentEditor.isValueChanged()) {
+ var validationResults = currentEditor.validate();
+
+ if (validationResults.valid) {
+ if (activeRow < getDataLength()) {
+ var editCommand = {
+ row: activeRow,
+ cell: activeCell,
+ editor: currentEditor,
+ serializedValue: currentEditor.serializeValue(),
+ prevSerializedValue: serializedEditorValue,
+ execute: function () {
+ this.editor.applyValue(item, this.serializedValue);
+ updateRow(this.row);
+ trigger(self.onCellChange, {
+ row: activeRow,
+ cell: activeCell,
+ item: item,
+ grid: self
+ });
+ },
+ undo: function () {
+ this.editor.applyValue(item, this.prevSerializedValue);
+ updateRow(this.row);
+ trigger(self.onCellChange, {
+ row: activeRow,
+ cell: activeCell,
+ item: item,
+ grid: self
+ });
+ }
+ };
+
+ if (options.editCommandHandler) {
+ makeActiveCellNormal();
+ options.editCommandHandler(item, column, editCommand);
+ } else {
+ editCommand.execute();
+ makeActiveCellNormal();
+ }
+
+ } else {
+ var newItem = {};
+ currentEditor.applyValue(newItem, currentEditor.serializeValue());
+ makeActiveCellNormal();
+ trigger(self.onAddNewRow, {item: newItem, column: column, grid: self});
+ }
+
+ // check whether the lock has been re-acquired by event handlers
+ return !getEditorLock().isActive();
+ } else {
+ // Re-add the CSS class to trigger transitions, if any.
+ $(activeCellNode).removeClass("invalid");
+ $(activeCellNode).width(); // force layout
+ $(activeCellNode).addClass("invalid");
+
+ trigger(self.onValidationError, {
+ editor: currentEditor,
+ cellNode: activeCellNode,
+ validationResults: validationResults,
+ row: activeRow,
+ cell: activeCell,
+ column: column,
+ grid: self
+ });
+
+ currentEditor.focus();
+ return false;
+ }
+ }
+
+ makeActiveCellNormal();
+ }
+ return true;
+ }
+
+ function cancelCurrentEdit() {
+ makeActiveCellNormal();
+ return true;
+ }
+
+ function rowsToRanges(rows) {
+ var ranges = [];
+ var lastCell = columns.length - 1;
+ for (var i = 0; i < rows.length; i++) {
+ ranges.push(new Slick.Range(rows[i], 0, rows[i], lastCell));
+ }
+ return ranges;
+ }
+
+ function getSelectedRows() {
+ if (!selectionModel) {
+ throw new Error("Selection model is not set");
+ }
+ return selectedRows;
+ }
+
+ function setSelectedRows(rows) {
+ if (!selectionModel) {
+ throw new Error("Selection model is not set");
+ }
+ selectionModel.setSelectedRanges(rowsToRanges(rows));
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Debug
+
+ this.debug = function () {
+ var s = "";
+
+ s += ("\n" + "counter_rows_rendered: " + counter_rows_rendered);
+ s += ("\n" + "counter_rows_removed: " + counter_rows_removed);
+ s += ("\n" + "renderedRows: " + renderedRows);
+ s += ("\n" + "numVisibleRows: " + numVisibleRows);
+ s += ("\n" + "maxSupportedCssHeight: " + maxSupportedCssHeight);
+ s += ("\n" + "n(umber of pages): " + n);
+ s += ("\n" + "(current) page: " + page);
+ s += ("\n" + "page height (ph): " + ph);
+ s += ("\n" + "vScrollDir: " + vScrollDir);
+
+ alert(s);
+ };
+
+ // a debug helper to be able to access private members
+ this.eval = function (expr) {
+ return eval(expr);
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Public API
+
+ $.extend(this, {
+ "slickGridVersion": "2.3.4",
+
+ // Events
+ "onScroll": new Slick.Event(),
+ "onSort": new Slick.Event(),
+ "onHeaderMouseEnter": new Slick.Event(),
+ "onHeaderMouseLeave": new Slick.Event(),
+ "onHeaderContextMenu": new Slick.Event(),
+ "onHeaderClick": new Slick.Event(),
+ "onHeaderCellRendered": new Slick.Event(),
+ "onBeforeHeaderCellDestroy": new Slick.Event(),
+ "onHeaderRowCellRendered": new Slick.Event(),
+ "onFooterRowCellRendered": new Slick.Event(),
+ "onBeforeHeaderRowCellDestroy": new Slick.Event(),
+ "onBeforeFooterRowCellDestroy": new Slick.Event(),
+ "onMouseEnter": new Slick.Event(),
+ "onMouseLeave": new Slick.Event(),
+ "onClick": new Slick.Event(),
+ "onDblClick": new Slick.Event(),
+ "onContextMenu": new Slick.Event(),
+ "onKeyDown": new Slick.Event(),
+ "onAddNewRow": new Slick.Event(),
+ "onBeforeAppendCell": new Slick.Event(),
+ "onValidationError": new Slick.Event(),
+ "onViewportChanged": new Slick.Event(),
+ "onColumnsReordered": new Slick.Event(),
+ "onColumnsResized": new Slick.Event(),
+ "onCellChange": new Slick.Event(),
+ "onBeforeEditCell": new Slick.Event(),
+ "onBeforeCellEditorDestroy": new Slick.Event(),
+ "onBeforeDestroy": new Slick.Event(),
+ "onActiveCellChanged": new Slick.Event(),
+ "onActiveCellPositionChanged": new Slick.Event(),
+ "onDragInit": new Slick.Event(),
+ "onDragStart": new Slick.Event(),
+ "onDrag": new Slick.Event(),
+ "onDragEnd": new Slick.Event(),
+ "onSelectedRowsChanged": new Slick.Event(),
+ "onCellCssStylesChanged": new Slick.Event(),
+
+ // Methods
+ "registerPlugin": registerPlugin,
+ "unregisterPlugin": unregisterPlugin,
+ "getColumns": getColumns,
+ "setColumns": setColumns,
+ "getColumnIndex": getColumnIndex,
+ "updateColumnHeader": updateColumnHeader,
+ "setSortColumn": setSortColumn,
+ "setSortColumns": setSortColumns,
+ "getSortColumns": getSortColumns,
+ "autosizeColumns": autosizeColumns,
+ "getOptions": getOptions,
+ "setOptions": setOptions,
+ "getData": getData,
+ "getDataLength": getDataLength,
+ "getDataItem": getDataItem,
+ "setData": setData,
+ "getSelectionModel": getSelectionModel,
+ "setSelectionModel": setSelectionModel,
+ "getSelectedRows": getSelectedRows,
+ "setSelectedRows": setSelectedRows,
+ "getContainerNode": getContainerNode,
+ "updatePagingStatusFromView": updatePagingStatusFromView,
+
+ "render": render,
+ "invalidate": invalidate,
+ "invalidateRow": invalidateRow,
+ "invalidateRows": invalidateRows,
+ "invalidateAllRows": invalidateAllRows,
+ "updateCell": updateCell,
+ "updateRow": updateRow,
+ "getViewport": getVisibleRange,
+ "getRenderedRange": getRenderedRange,
+ "resizeCanvas": resizeCanvas,
+ "updateRowCount": updateRowCount,
+ "scrollRowIntoView": scrollRowIntoView,
+ "scrollRowToTop": scrollRowToTop,
+ "scrollCellIntoView": scrollCellIntoView,
+ "getCanvasNode": getCanvasNode,
+ "focus": setFocus,
+
+ "getCellFromPoint": getCellFromPoint,
+ "getCellFromEvent": getCellFromEvent,
+ "getActiveCell": getActiveCell,
+ "setActiveCell": setActiveCell,
+ "getActiveCellNode": getActiveCellNode,
+ "getActiveCellPosition": getActiveCellPosition,
+ "resetActiveCell": resetActiveCell,
+ "editActiveCell": makeActiveCellEditable,
+ "getCellEditor": getCellEditor,
+ "getCellNode": getCellNode,
+ "getCellNodeBox": getCellNodeBox,
+ "canCellBeSelected": canCellBeSelected,
+ "canCellBeActive": canCellBeActive,
+ "navigatePrev": navigatePrev,
+ "navigateNext": navigateNext,
+ "navigateUp": navigateUp,
+ "navigateDown": navigateDown,
+ "navigateLeft": navigateLeft,
+ "navigateRight": navigateRight,
+ "navigatePageUp": navigatePageUp,
+ "navigatePageDown": navigatePageDown,
+ "gotoCell": gotoCell,
+ "getTopPanel": getTopPanel,
+ "setTopPanelVisibility": setTopPanelVisibility,
+ "setHeaderRowVisibility": setHeaderRowVisibility,
+ "getHeaderRow": getHeaderRow,
+ "getHeaderRowColumn": getHeaderRowColumn,
+ "setFooterRowVisibility": setFooterRowVisibility,
+ "getFooterRow": getFooterRow,
+ "getFooterRowColumn": getFooterRowColumn,
+ "getGridPosition": getGridPosition,
+ "flashCell": flashCell,
+ "addCellCssStyles": addCellCssStyles,
+ "setCellCssStyles": setCellCssStyles,
+ "removeCellCssStyles": removeCellCssStyles,
+ "getCellCssStyles": getCellCssStyles,
+
+ "init": finishInitialization,
+ "destroy": destroy,
+
+ // IEditor implementation
+ "getEditorLock": getEditorLock,
+ "getEditController": getEditController
+ });
+
+ init();
+ }
+}(jQuery));
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.groupitemmetadataprovider.js b/web/pgadmin/static/vendor/slickgrid/slick.groupitemmetadataprovider.js
new file mode 100644
index 00000000..de05c721
--- /dev/null
+++ b/web/pgadmin/static/vendor/slickgrid/slick.groupitemmetadataprovider.js
@@ -0,0 +1,158 @@
+(function ($) {
+ $.extend(true, window, {
+ Slick: {
+ Data: {
+ GroupItemMetadataProvider: GroupItemMetadataProvider
+ }
+ }
+ });
+
+
+ /***
+ * Provides item metadata for group (Slick.Group) and totals (Slick.Totals) rows produced by the DataView.
+ * This metadata overrides the default behavior and formatting of those rows so that they appear and function
+ * correctly when processed by the grid.
+ *
+ * This class also acts as a grid plugin providing event handlers to expand & collapse groups.
+ * If "grid.registerPlugin(...)" is not called, expand & collapse will not work.
+ *
+ * @class GroupItemMetadataProvider
+ * @module Data
+ * @namespace Slick.Data
+ * @constructor
+ * @param options
+ */
+ function GroupItemMetadataProvider(options) {
+ var _grid;
+ var _defaults = {
+ groupCssClass: "slick-group",
+ groupTitleCssClass: "slick-group-title",
+ totalsCssClass: "slick-group-totals",
+ groupFocusable: true,
+ totalsFocusable: false,
+ toggleCssClass: "slick-group-toggle",
+ toggleExpandedCssClass: "expanded",
+ toggleCollapsedCssClass: "collapsed",
+ enableExpandCollapse: true,
+ groupFormatter: defaultGroupCellFormatter,
+ totalsFormatter: defaultTotalsCellFormatter
+ };
+
+ options = $.extend(true, {}, _defaults, options);
+
+
+ function defaultGroupCellFormatter(row, cell, value, columnDef, item) {
+ if (!options.enableExpandCollapse) {
+ return item.title;
+ }
+
+ var indentation = item.level * 15 + "px";
+
+ return "<span class='" + options.toggleCssClass + " " +
+ (item.collapsed ? options.toggleCollapsedCssClass : options.toggleExpandedCssClass) +
+ "' style='margin-left:" + indentation +"'>" +
+ "</span>" +
+ "<span class='" + options.groupTitleCssClass + "' level='" + item.level + "'>" +
+ item.title +
+ "</span>";
+ }
+
+ function defaultTotalsCellFormatter(row, cell, value, columnDef, item) {
+ return (columnDef.groupTotalsFormatter && columnDef.groupTotalsFormatter(item, columnDef)) || "";
+ }
+
+
+ function init(grid) {
+ _grid = grid;
+ _grid.onClick.subscribe(handleGridClick);
+ _grid.onKeyDown.subscribe(handleGridKeyDown);
+
+ }
+
+ function destroy() {
+ if (_grid) {
+ _grid.onClick.unsubscribe(handleGridClick);
+ _grid.onKeyDown.unsubscribe(handleGridKeyDown);
+ }
+ }
+
+ function handleGridClick(e, args) {
+ var item = this.getDataItem(args.row);
+ if (item && item instanceof Slick.Group && $(e.target).hasClass(options.toggleCssClass)) {
+ var range = _grid.getRenderedRange();
+ this.getData().setRefreshHints({
+ ignoreDiffsBefore: range.top,
+ ignoreDiffsAfter: range.bottom + 1
+ });
+
+ if (item.collapsed) {
+ this.getData().expandGroup(item.groupingKey);
+ } else {
+ this.getData().collapseGroup(item.groupingKey);
+ }
+
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ }
+ }
+
+ // TODO: add -/+ handling
+ function handleGridKeyDown(e, args) {
+ if (options.enableExpandCollapse && (e.which == $.ui.keyCode.SPACE)) {
+ var activeCell = this.getActiveCell();
+ if (activeCell) {
+ var item = this.getDataItem(activeCell.row);
+ if (item && item instanceof Slick.Group) {
+ var range = _grid.getRenderedRange();
+ this.getData().setRefreshHints({
+ ignoreDiffsBefore: range.top,
+ ignoreDiffsAfter: range.bottom + 1
+ });
+
+ if (item.collapsed) {
+ this.getData().expandGroup(item.groupingKey);
+ } else {
+ this.getData().collapseGroup(item.groupingKey);
+ }
+
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ }
+ }
+ }
+ }
+
+ function getGroupRowMetadata(item) {
+ return {
+ selectable: false,
+ focusable: options.groupFocusable,
+ cssClasses: options.groupCssClass,
+ columns: {
+ 0: {
+ colspan: "*",
+ formatter: options.groupFormatter,
+ editor: null
+ }
+ }
+ };
+ }
+
+ function getTotalsRowMetadata(item) {
+ return {
+ selectable: false,
+ focusable: options.totalsFocusable,
+ cssClasses: options.totalsCssClass,
+ formatter: options.totalsFormatter,
+ editor: null
+ };
+ }
+
+
+ return {
+ "init": init,
+ "destroy": destroy,
+ "getGroupRowMetadata": getGroupRowMetadata,
+ "getTotalsRowMetadata": getTotalsRowMetadata
+ };
+ }
+})(jQuery);
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.remotemodel-yahoo.js b/web/pgadmin/static/vendor/slickgrid/slick.remotemodel-yahoo.js
new file mode 100644
index 00000000..fb11d85a
--- /dev/null
+++ b/web/pgadmin/static/vendor/slickgrid/slick.remotemodel-yahoo.js
@@ -0,0 +1,206 @@
+(function ($) {
+ /***
+ * A sample AJAX data store implementation.
+ * Right now, it's hooked up to load Hackernews stories, but can
+ * easily be extended to support any JSONP-compatible backend that accepts paging parameters.
+ */
+ function RemoteModel() {
+ // private
+ var PAGESIZE = 10;
+ var data = {length: 0};
+ var h_request = null;
+ var req = null; // ajax request
+
+ // events
+ var onDataLoading = new Slick.Event();
+ var onDataLoaded = new Slick.Event();
+
+
+ function init() {
+ }
+
+
+ function isDataLoaded(from, to) {
+ for (var i = from; i <= to; i++) {
+ if (data[i] == undefined || data[i] == null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ function clear() {
+ for (var key in data) {
+ delete data[key];
+ }
+ data.length = 0;
+ }
+
+ function ensureData(from, to) {
+ if (req) {
+ req.abort();
+ for (var i = req.fromPage; i <= req.toPage; i++) {
+ data[i * PAGESIZE] = undefined;
+ }
+ }
+
+ if (from < 0) {
+ from = 0;
+ }
+
+ if (data.length > 0) {
+ to = Math.min(to, data.length - 1);
+ }
+
+ var fromPage = Math.floor(from / PAGESIZE);
+ var toPage = Math.floor(to / PAGESIZE);
+
+ while (data[fromPage * PAGESIZE] !== undefined && fromPage < toPage)
+ fromPage++;
+
+ while (data[toPage * PAGESIZE] !== undefined && fromPage < toPage)
+ toPage--;
+
+ if (fromPage > toPage || ((fromPage == toPage) && data[fromPage * PAGESIZE] !== undefined)) {
+ // TODO: look-ahead
+ onDataLoaded.notify({from: from, to: to});
+ return;
+ }
+
+ var recStart = (fromPage * PAGESIZE);
+ var recCount = (((toPage - fromPage) * PAGESIZE) + PAGESIZE);
+
+ var url = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20rss"
+ + "(" + recStart + "%2C" + recCount + ")"
+ + "%20where%20url%3D%22http%3A%2F%2Frss.news.yahoo.com%2Frss%2Ftopstories%22"
+ + "&format=json";
+
+ if (h_request != null) {
+ clearTimeout(h_request);
+ }
+
+ h_request = setTimeout(function () {
+ for (var i = fromPage; i <= toPage; i++)
+ data[i * PAGESIZE] = null; // null indicates a 'requested but not available yet'
+
+ onDataLoading.notify({from: from, to: to});
+
+ req = $.jsonp({
+ url: url,
+ callbackParameter: "callback",
+ cache: true,
+ success: function (json, textStatus, xOptions) {
+ onSuccess(json, recStart)
+ },
+ error: function () {
+ onError(fromPage, toPage)
+ }
+ });
+
+ req.fromPage = fromPage;
+ req.toPage = toPage;
+ }, 50);
+ }
+
+
+ function onError(fromPage, toPage) {
+ alert("error loading pages " + fromPage + " to " + toPage);
+ }
+
+// SAMPLE DATA
+// {
+// "query": {
+// "count": 40,
+// "created": "2015-03-03T00:34:00Z",
+// "lang": "en-US",
+// "results": {
+// "item": [
+// {
+// "title": "Netanyahu assails Iran deal, touts US-Israel ties",
+// "description": "<p><a href=\"http://news.yahoo.com/netanyahu-us-officials-face-off-iran-133539021--politics.html\"><img src=\"http://l2.yimg.com/bt/api/res/1.2/4eoBxbJStrbGAKbmBYOJfg--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9NzU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/2f3a20c2d46d9f096f0f6a706700d430.jpg\" width=\"130\" height=\"86\" alt=\"Israeli Prime Minister Benjamin Netanyahu addresses the 2015 American Israel Public Affairs Committee (AIPAC) Policy Conference in Washington, Monday, March 2, 2015. (AP Photo/Cliff Owen)\" align=\"left\" title=\"Israeli Prime Minister Benjamin Netanyahu addresses the 2015 American Israel Public Affairs Committee (AIPAC) Policy Conference in Washington, Monday, March 2, 2015. (AP Photo/Cliff Owen)\" border=\"0\" /></a>WASHINGTON (AP) — Seeking to lower tensions, Benjamin Netanyahu and U.S. officials cast their dispute over Iran as a family squabble on Monday, even as the Israeli leader claimed President Barack Obama did not — and could not — fully understand his nation's vital security concerns.</p><br clear=\"all\"/>",
+// "link": "http://news.yahoo.com/netanyahu-us-officials-face-off-iran-133539021--politics.html",
+// "pubDate": "Mon, 02 Mar 2015 19:17:36 -0500",
+// "source": {
+// "url": "http://www.ap.org/",
+// "content": "Associated Press"
+// },
+// "guid": {
+// "isPermaLink": "false",
+// "content": "netanyahu-us-officials-face-off-iran-133539021--politics"
+// },
+// "content": {
+// "height": "86",
+// "type": "image/jpeg",
+// "url": "http://l2.yimg.com/bt/api/res/1.2/4eoBxbJStrbGAKbmBYOJfg--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9NzU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/2f3a20c2d46d9f096f0f6a706700d430.jpg",
+// "width": "130"
+// },
+// "text": {
+// "type": "html",
+// "content": "<p><a href=\"http://news.yahoo.com/netanyahu-us-officials-face-off-iran-133539021--politics.html\"><img src=\"http://l2.yimg.com/bt/api/res/1.2/4eoBxbJStrbGAKbmBYOJfg--/YXBwaWQ9eW5ld3M7Zmk9ZmlsbDtoPTg2O3E9NzU7dz0xMzA-/http://media.zenfs.com/en_us/News/ap_webfeeds/2f3a20c2d46d9f096f0f6a706700d430.jpg\" width=\"130\" height=\"86\" alt=\"Israeli Prime Minister Benjamin Netanyahu addresses the 2015 American Israel Public Affairs Committee (AIPAC) Policy Conference in Washington, Monday, March 2, 2015. (AP Photo/Cliff Owen)\" align=\"left\" title=\"Israeli Prime Minister Benjamin Netanyahu addresses the 2015 American Israel Public Affairs Committee (AIPAC) Policy Conference in Washington, Monday, March 2, 2015. (AP Photo/Cliff Owen)\" border=\"0\" /></a>WASHINGTON (AP) — Seeking to lower tensions, Benjamin Netanyahu and U.S. officials cast their dispute over Iran as a family squabble on Monday, even as the Israeli leader claimed President Barack Obama did not — and could not — fully understand his nation's vital security concerns.</p><br clear=\"all\"/>"
+// },
+// "credit": {
+// "role": "publishing company"
+// }
+// },
+// {... },
+// {... },
+// ]
+// }
+// }
+// }
+
+ function onSuccess(json, recStart) {
+ var recEnd = recStart;
+ if (json.query.count > 0) {
+ var results = json.query.results.item;
+ recEnd = recStart + results.length;
+ data.length = 100;// Math.min(parseInt(results.length),1000); // limitation of the API
+
+ for (var i = 0; i < results.length; i++) {
+ var item = results[i];
+
+ item.pubDate = new Date(item.pubDate);
+
+ data[recStart + i] = { index: recStart + i };
+ data[recStart + i].pubDate = item.pubDate;
+ data[recStart + i].title = item.title;
+ data[recStart + i].url = item.link;
+ data[recStart + i].text = item.description;
+ }
+ }
+ req = null;
+
+ onDataLoaded.notify({from: recStart, to: recEnd});
+ }
+
+
+ function reloadData(from, to) {
+ for (var i = from; i <= to; i++)
+ delete data[i];
+
+ ensureData(from, to);
+ }
+
+ init();
+
+ return {
+ // properties
+ "data": data,
+
+ // methods
+ "clear": clear,
+ "isDataLoaded": isDataLoaded,
+ "ensureData": ensureData,
+ "reloadData": reloadData,
+
+ // events
+ "onDataLoading": onDataLoading,
+ "onDataLoaded": onDataLoaded
+ };
+ }
+
+ // Slick.Data.RemoteModel
+ $.extend(true, window, { Slick: { Data: { RemoteModel: RemoteModel }}});
+})(jQuery);
diff --git a/web/pgadmin/static/vendor/slickgrid/slick.remotemodel.js b/web/pgadmin/static/vendor/slickgrid/slick.remotemodel.js
new file mode 100644
index 00000000..f81ca3f4
--- /dev/null
+++ b/web/pgadmin/static/vendor/slickgrid/slick.remotemodel.js
@@ -0,0 +1,169 @@
+(function ($) {
+ /***
+ * A sample AJAX data store implementation.
+ * Right now, it's hooked up to load search results from Octopart, but can
+ * easily be extended to support any JSONP-compatible backend that accepts paging parameters.
+ */
+ function RemoteModel() {
+ // private
+ var PAGESIZE = 50;
+ var data = {length: 0};
+ var searchstr = "";
+ var sortcol = null;
+ var sortdir = 1;
+ var h_request = null;
+ var req = null; // ajax request
+
+ // events
+ var onDataLoading = new Slick.Event();
+ var onDataLoaded = new Slick.Event();
+
+
+ function init() {
+ }
+
+
+ function isDataLoaded(from, to) {
+ for (var i = from; i <= to; i++) {
+ if (data[i] == undefined || data[i] == null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ function clear() {
+ for (var key in data) {
+ delete data[key];
+ }
+ data.length = 0;
+ }
+
+
+ function ensureData(from, to) {
+ if (req) {
+ req.abort();
+ for (var i = req.fromPage; i <= req.toPage; i++)
+ data[i * PAGESIZE] = undefined;
+ }
+
+ if (from < 0) {
+ from = 0;
+ }
+
+ if (data.length > 0) {
+ to = Math.min(to, data.length - 1);
+ }
+
+ var fromPage = Math.floor(from / PAGESIZE);
+ var toPage = Math.floor(to / PAGESIZE);
+
+ while (data[fromPage * PAGESIZE] !== undefined && fromPage < toPage)
+ fromPage++;
+
+ while (data[toPage * PAGESIZE] !== undefined && fromPage < toPage)
+ toPage--;
+
+ if (fromPage > toPage || ((fromPage == toPage) && data[fromPage * PAGESIZE] !== undefined)) {
+ // TODO: look-ahead
+ onDataLoaded.notify({from: from, to: to});
+ return;
+ }
+
+ var url = "http://octopart.com/api/v3/parts/search?apikey=68b25f31&include[]=short_description&show[]=uid&show[]=manufacturer&show[]=mpn&show[]=brand&show[]=octopart_url&show[]=short_description&q=" + searchstr + "&start=" + (fromPage * PAGESIZE) + "&limit=" + (((toPage - fromPage) * PAGESIZE) + PAGESIZE);
+
+ if (sortcol != null) {
+ url += ("&sortby=" + sortcol + ((sortdir > 0) ? "+asc" : "+desc"));
+ }
+
+ if (h_request != null) {
+ clearTimeout(h_request);
+ }
+
+ h_request = setTimeout(function () {
+ for (var i = fromPage; i <= toPage; i++)
+ data[i * PAGESIZE] = null; // null indicates a 'requested but not available yet'
+
+ onDataLoading.notify({from: from, to: to});
+
+ req = $.jsonp({
+ url: url,
+ callbackParameter: "callback",
+ cache: true,
+ success: onSuccess,
+ error: function () {
+ onError(fromPage, toPage)
+ }
+ });
+ req.fromPage = fromPage;
+ req.toPage = toPage;
+ }, 50);
+ }
+
+
+ function onError(fromPage, toPage) {
+ alert("error loading pages " + fromPage + " to " + toPage);
+ }
+
+ function onSuccess(resp) {
+ var from = resp.request.start, to = from + resp.results.length;
+ data.length = Math.min(parseInt(resp.hits),1000); // limitation of the API
+
+ for (var i = 0; i < resp.results.length; i++) {
+ var item = resp.results[i].item;
+
+ data[from + i] = item;
+ data[from + i].index = from + i;
+ }
+
+ req = null;
+
+ onDataLoaded.notify({from: from, to: to});
+ }
+
+
+ function reloadData(from, to) {
+ for (var i = from; i <= to; i++)
+ delete data[i];
+
+ ensureData(from, to);
+ }
+
+
+ function setSort(column, dir) {
+ sortcol = column;
+ sortdir = dir;
+ clear();
+ }
+
+ function setSearch(str) {
+ searchstr = str;
+ clear();
+ }
+
+
+ init();
+
+ return {
+ // properties
+ "data": data,
+
+ // methods
+ "clear": clear,
+ "isDataLoaded": isDataLoaded,
+ "ensureData": ensureData,
+ "reloadData": reloadData,
+ "setSort": setSort,
+ "setSearch": setSearch,
+
+ // events
+ "onDataLoading": onDataLoading,
+ "onDataLoaded": onDataLoaded
+ };
+ }
+
+ // Slick.Data.RemoteModel
+ $.extend(true, window, { Slick: { Data: { RemoteModel: RemoteModel }}});
+})(jQuery);
\ No newline at end of file
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index 574ef53a..b8e979d4 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -279,7 +279,7 @@ li {
background-color: white;
}
-.sc.cell-move-handle {
+.slick-cell.cell-move-handle {
font-weight: bold;
text-align: right;
border-right: solid gray;
@@ -291,15 +291,15 @@ li {
background: #b6b9bd;
}
-.sr.selected .cell-move-handle {
+.slick-row.selected .cell-move-handle {
background: #D5DC8D;
}
-.sr .cell-actions {
+.slick-row .cell-actions {
text-align: left;
}
-.sr.complete {
+.slick-row.complete {
background-color: #DFD;
color: #555;
}
@@ -332,7 +332,7 @@ li {
font-size: 10px;
}
-.sr.selected .cell-selection {
+.slick-row.selected .cell-selection {
background-color: transparent; /* show default selected row background */
}
@@ -401,7 +401,7 @@ input.editor-checkbox:focus {
}
/* Override selected row color */
-.sc.selected {
+.slick-cell.selected {
background-color: #DEE8F1 !important;
}
@@ -421,7 +421,7 @@ input.editor-checkbox:focus {
}
/* color the first column */
-.sr .sc:first-child {
+.slick-row .slick-cell:first-child {
background-color: #2c76b4;
}
@@ -443,6 +443,6 @@ input.editor-checkbox:focus {
-ms-box-sizing: content-box;
}
-.sr.ui-widget-content {
+.slick-row.ui-widget-content {
border-top: 1px solid silver;
}
diff --git a/web/regression/javascript/selection/row_selector_spec.js b/web/regression/javascript/selection/row_selector_spec.js
index 10697e6a..2fa61029 100644
--- a/web/regression/javascript/selection/row_selector_spec.js
+++ b/web/regression/javascript/selection/row_selector_spec.js
@@ -54,8 +54,8 @@ define(
});
it("renders a checkbox the leftmost column", function () {
- expect(container.find('.sr').length).toBe(11);
- expect(container.find('.sr .sc:first-child input[type="checkbox"]').length).toBe(10);
+ expect(container.find('.slick-row').length).toBe(10);
+ expect(container.find('.slick-row .slick-cell:first-child input[type="checkbox"]').length).toBe(10);
});
it("preserves the other attributes of column definitions", function () {
@@ -66,40 +66,40 @@ define(
describe("selecting rows", function () {
describe("when the user clicks a row header checkbox", function () {
it("selects the row", function () {
- container.find('.sr .sc:first-child input[type="checkbox"]')[0].click();
+ container.find('.slick-row .slick-cell:first-child input[type="checkbox"]')[0].click();
var selectedRanges = rowSelectionModel.getSelectedRanges();
expectOnlyTheFirstRowToBeSelected(selectedRanges);
});
it("checks the checkbox", function () {
- container.find('.sr .sc:first-child input[type="checkbox"]')[5].click();
+ container.find('.slick-row .slick-cell:first-child input[type="checkbox"]')[5].click();
- expect($(container.find('.sr .sc:first-child input[type="checkbox"]')[5])
+ expect($(container.find('.slick-row .slick-cell:first-child input[type="checkbox"]')[5])
.is(':checked')).toBeTruthy();
});
});
describe("when the user clicks a row header", function () {
it("selects the row", function () {
- container.find('.sr .sc:first-child')[0].click();
+ container.find('.slick-row .slick-cell:first-child')[0].click();
var selectedRanges = rowSelectionModel.getSelectedRanges();
expectOnlyTheFirstRowToBeSelected(selectedRanges);
});
it("checks the checkbox", function () {
- container.find('.sr .sc:first-child')[7].click();
+ container.find('.slick-row .slick-cell:first-child')[7].click();
- expect($(container.find('.sr .sc:first-child input[type="checkbox"]')[7])
+ expect($(container.find('.slick-row .slick-cell:first-child input[type="checkbox"]')[7])
.is(':checked')).toBeTruthy();
});
});
describe("when the user clicks multiple row headers", function () {
it("selects another row", function () {
- container.find('.sr .sc:first-child')[4].click();
- container.find('.sr .sc:first-child')[0].click();
+ container.find('.slick-row .slick-cell:first-child')[4].click();
+ container.find('.slick-row .slick-cell:first-child')[0].click();
var selectedRanges = rowSelectionModel.getSelectedRanges();
expect(selectedRanges.length).toEqual(2);
@@ -121,7 +121,7 @@ define(
});
it("deselects the column", function () {
- container.find('.sr .sc:first-child')[0].click();
+ container.find('.slick-row .slick-cell:first-child')[0].click();
var selectedRanges = rowSelectionModel.getSelectedRanges();
expectOnlyTheFirstRowToBeSelected(selectedRanges);
@@ -130,30 +130,30 @@ define(
describe("when the row is deselected through setSelectedRanges", function () {
beforeEach(function () {
- container.find('.sr .sc:first-child')[4].click();
+ container.find('.slick-row .slick-cell:first-child')[4].click();
});
it("should uncheck the checkbox", function () {
rowSelectionModel.setSelectedRanges([]);
- expect($(container.find('.sr .sc:first-child input[type="checkbox"]')[4])
+ expect($(container.find('.slick-row .slick-cell:first-child input[type="checkbox"]')[4])
.is(':checked')).toBeFalsy();
});
});
describe("click a second time", function () {
beforeEach(function () {
- container.find('.sr .sc:first-child')[1].click();
+ container.find('.slick-row .slick-cell:first-child')[1].click();
});
it("unchecks checkbox", function () {
- container.find('.sr .sc:first-child')[1].click();
- expect($(container.find('.sr .sc:first-child input[type="checkbox"]')[1])
+ container.find('.slick-row .slick-cell:first-child')[1].click();
+ expect($(container.find('.slick-row .slick-cell:first-child input[type="checkbox"]')[1])
.is(':checked')).toBeFalsy();
});
it("unselects the row", function () {
- container.find('.sr .sc:first-child')[1].click();
+ container.find('.slick-row .slick-cell:first-child')[1].click();
var selectedRanges = rowSelectionModel.getSelectedRanges();
expect(selectedRanges.length).toEqual(0);
--
2.12.0
^ permalink raw reply [nested|flat] 9+ messages in thread
* Re: Issue with SlickGrid
2017-04-26 20:53 Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 06:39 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 06:46 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 11:12 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 12:13 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 15:49 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
@ 2017-04-27 15:53 ` Dave Page <[email protected]>
2017-05-03 04:26 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
0 siblings, 1 reply; 9+ messages in thread
From: Dave Page @ 2017-04-27 15:53 UTC (permalink / raw)
To: Joao Pedro De Almeida Pereira <[email protected]>; +Cc: Murtuza Zabuawala <[email protected]>; pgadmin-hackers; Matthew Kleiman <[email protected]>
Thanks Joao. Murtuza, can you review this please?
On Thu, Apr 27, 2017 at 4:49 PM, Joao Pedro De Almeida Pereira <
[email protected]> wrote:
> Hi Hackers,
>
> We found that the latest version of SlickGrid fixes the scrollbar issue.
> We have upgraded it to the latest version in our vendor directory and
> updated the tests accordingly in the attached patch.
>
> We didn't apply any of the custom changes that were previously added.
> Please validate that the memory issues that were referenced in the README
> file are solved with the latest version of SlickGrid. If we can avoid
> changing the code of the libraries that we use, it will be far easier to
> continue to upgrade in the future. We will need to upgrade the version of
> SlickGrid again soon, once they approve our pull request
> <https://github.com/6pac/SlickGrid/pull/100;.
>
> Thanks,
> Joao & Matt
>
>
> On Thu, Apr 27, 2017 at 8:13 AM, Murtuza Zabuawala <murtuza.zabuawala@
> enterprisedb.com> wrote:
>
>> No, we didn't.
>>
>> --
>> Regards,
>> Murtuza Zabuawala
>> EnterpriseDB: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>> On Thu, Apr 27, 2017 at 4:42 PM, Joao Pedro De Almeida Pereira <
>> [email protected]> wrote:
>>
>>> Hello Murtuza,
>>> Thanks for the explanation. Based on what you said it looks like a bug
>>> in the library, have you guys considered sending a PR to it?
>>>
>>> Thanks
>>>
>>> On Thu, Apr 27, 2017, 2:46 AM Murtuza Zabuawala <
>>> [email protected]> wrote:
>>>
>>>> +++
>>>> Reference: https://www.postgresql.org/message-id/CAKKotZRjqb
>>>> KAZev81Zk78nikDVXqLKEDV5r%2BsW8Me31Gpzrm_A%40mail.gmail.com
>>>>
>>>> --
>>>> Regards,
>>>> Murtuza Zabuawala
>>>> EnterpriseDB: http://www.enterprisedb.com
>>>> The Enterprise PostgreSQL Company
>>>>
>>>> On Thu, Apr 27, 2017 at 12:09 PM, Murtuza Zabuawala <
>>>> [email protected]> wrote:
>>>>
>>>>> Hello Joao,
>>>>>
>>>>> Yes, We made some changes in SlickGrid library when we integrated it
>>>>> into Query tool.
>>>>>
>>>>> *Issue:* Last row from the query result set was not displaying
>>>>> correctly in query tool when we have scrollbar in grid.
>>>>>
>>>>> The row hight/width pixel size calculations is done inside SlickGrid
>>>>> javascript code, Though we tried solve it through CSS but we had no luck,
>>>>> so we had no other choice but to do it in library it self.
>>>>>
>>>>> The changes were,
>>>>> 1) "getDataLengthIncludingAddNew()" function (slick.grid.js) to add
>>>>> two new rows instead of one when user add values into row (one row is dummy
>>>>> & not visible to user so that it displays last row correctly)
>>>>> 2) Other change was done into "appendRowHtml()" function to
>>>>> calculating the correct number of rows in SlickGrid result as we have added
>>>>> our own custom row as mentioned earlier.
>>>>> 3) Abbreviated long CSS classes as mentioed in README file.
>>>>>
>>>>> Apologies we missed to update this change in README.
>>>>>
>>>>>
>>>>> --
>>>>> Regards,
>>>>> Murtuza Zabuawala
>>>>> EnterpriseDB: http://www.enterprisedb.com
>>>>> The Enterprise PostgreSQL Company
>>>>>
>>>>> On Thu, Apr 27, 2017 at 2:23 AM, Joao Pedro De Almeida Pereira <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hello Hackers,
>>>>>>
>>>>>> While doing some changes to the Query Results we found out that there
>>>>>> was a issue with Slick grid.
>>>>>>
>>>>>> The issue that we found was with the CellSelectModel, behaved
>>>>>> differently when pressing Ctrl and Command(Mac). We created a PR
>>>>>> <https://github.com/6pac/SlickGrid/pull/100; with the change to
>>>>>> changes the behavior of the plugin.
>>>>>>
>>>>>> When this PR is applied to the SlickGrid library we need to apply it
>>>>>> to the current version of SlickGrid that we have vendorized.
>>>>>> According to the libraries.txt file we are in version 2.2.4 of the
>>>>>> library but a diff between our code and the libraries version 2.2.4 shows
>>>>>> differences in the code.
>>>>>>
>>>>>> Did we do any change to SlickGrid library that is vendorized? Or is
>>>>>> just the information in libraries.txt that is incorrect?
>>>>>> Does anyone know any problem if we bump the version of SlickGrid to
>>>>>> the newer version after the PR is applied?
>>>>>>
>>>>>> Thanks
>>>>>> Joao
>>>>>>
>>>>>
>>>>>
>>>>
>>
>
>
> --
> Sent via pgadmin-hackers mailing list ([email protected])
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgadmin-hackers
>
>
--
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake
EnterpriseDB UK: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
^ permalink raw reply [nested|flat] 9+ messages in thread
* Re: Issue with SlickGrid
2017-04-26 20:53 Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 06:39 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 06:46 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 11:12 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 12:13 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 15:49 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 15:53 ` Re: Issue with SlickGrid Dave Page <[email protected]>
@ 2017-05-03 04:26 ` Murtuza Zabuawala <[email protected]>
2017-05-05 21:44 ` Re: Issue with SlickGrid Sarah McAlear <[email protected]>
0 siblings, 1 reply; 9+ messages in thread
From: Murtuza Zabuawala @ 2017-05-03 04:26 UTC (permalink / raw)
To: Dave Page <[email protected]>; +Cc: Joao Pedro De Almeida Pereira <[email protected]>; pgadmin-hackers; Matthew Kleiman <[email protected]>
Hi Jao,
I found few minor issues,
1)
Individual cell selection is not visible,
This will be useful to user when user wants to use "By Selection" &
"Exclude Selection" filter option.
(Even if active cell is not visible to user, above filters are working
though when we click on any cell)
2)
Column header does not look good due bottom padding.
Refer screenshot.
3)
Select All color selection issue,
try running,
select * from pg_class
Now scroll horizontally till the last column and again scroll back to first
column,
you will see that one of the column gets the blue color as if it is
selected by user.
Refer screenshot.
Rest of the patch looks good to me.
--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Thu, Apr 27, 2017 at 9:23 PM, Dave Page <[email protected]> wrote:
> Thanks Joao. Murtuza, can you review this please?
>
> On Thu, Apr 27, 2017 at 4:49 PM, Joao Pedro De Almeida Pereira <
> [email protected]> wrote:
>
>> Hi Hackers,
>>
>> We found that the latest version of SlickGrid fixes the scrollbar issue.
>> We have upgraded it to the latest version in our vendor directory and
>> updated the tests accordingly in the attached patch.
>>
>> We didn't apply any of the custom changes that were previously added.
>> Please validate that the memory issues that were referenced in the README
>> file are solved with the latest version of SlickGrid. If we can avoid
>> changing the code of the libraries that we use, it will be far easier to
>> continue to upgrade in the future. We will need to upgrade the version of
>> SlickGrid again soon, once they approve our pull request
>> <https://github.com/6pac/SlickGrid/pull/100;.
>>
>> Thanks,
>> Joao & Matt
>>
>>
>> On Thu, Apr 27, 2017 at 8:13 AM, Murtuza Zabuawala <
>> [email protected]> wrote:
>>
>>> No, we didn't.
>>>
>>> --
>>> Regards,
>>> Murtuza Zabuawala
>>> EnterpriseDB: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>> On Thu, Apr 27, 2017 at 4:42 PM, Joao Pedro De Almeida Pereira <
>>> [email protected]> wrote:
>>>
>>>> Hello Murtuza,
>>>> Thanks for the explanation. Based on what you said it looks like a bug
>>>> in the library, have you guys considered sending a PR to it?
>>>>
>>>> Thanks
>>>>
>>>> On Thu, Apr 27, 2017, 2:46 AM Murtuza Zabuawala <
>>>> [email protected]> wrote:
>>>>
>>>>> +++
>>>>> Reference: https://www.postgresql.org/message-id/CAKKotZRjqb
>>>>> KAZev81Zk78nikDVXqLKEDV5r%2BsW8Me31Gpzrm_A%40mail.gmail.com
>>>>>
>>>>> --
>>>>> Regards,
>>>>> Murtuza Zabuawala
>>>>> EnterpriseDB: http://www.enterprisedb.com
>>>>> The Enterprise PostgreSQL Company
>>>>>
>>>>> On Thu, Apr 27, 2017 at 12:09 PM, Murtuza Zabuawala <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hello Joao,
>>>>>>
>>>>>> Yes, We made some changes in SlickGrid library when we integrated it
>>>>>> into Query tool.
>>>>>>
>>>>>> *Issue:* Last row from the query result set was not displaying
>>>>>> correctly in query tool when we have scrollbar in grid.
>>>>>>
>>>>>> The row hight/width pixel size calculations is done inside SlickGrid
>>>>>> javascript code, Though we tried solve it through CSS but we had no luck,
>>>>>> so we had no other choice but to do it in library it self.
>>>>>>
>>>>>> The changes were,
>>>>>> 1) "getDataLengthIncludingAddNew()" function (slick.grid.js) to add
>>>>>> two new rows instead of one when user add values into row (one row is dummy
>>>>>> & not visible to user so that it displays last row correctly)
>>>>>> 2) Other change was done into "appendRowHtml()" function to
>>>>>> calculating the correct number of rows in SlickGrid result as we have added
>>>>>> our own custom row as mentioned earlier.
>>>>>> 3) Abbreviated long CSS classes as mentioed in README file.
>>>>>>
>>>>>> Apologies we missed to update this change in README.
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Regards,
>>>>>> Murtuza Zabuawala
>>>>>> EnterpriseDB: http://www.enterprisedb.com
>>>>>> The Enterprise PostgreSQL Company
>>>>>>
>>>>>> On Thu, Apr 27, 2017 at 2:23 AM, Joao Pedro De Almeida Pereira <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hello Hackers,
>>>>>>>
>>>>>>> While doing some changes to the Query Results we found out that
>>>>>>> there was a issue with Slick grid.
>>>>>>>
>>>>>>> The issue that we found was with the CellSelectModel, behaved
>>>>>>> differently when pressing Ctrl and Command(Mac). We created a PR
>>>>>>> <https://github.com/6pac/SlickGrid/pull/100; with the change to
>>>>>>> changes the behavior of the plugin.
>>>>>>>
>>>>>>> When this PR is applied to the SlickGrid library we need to apply it
>>>>>>> to the current version of SlickGrid that we have vendorized.
>>>>>>> According to the libraries.txt file we are in version 2.2.4 of the
>>>>>>> library but a diff between our code and the libraries version 2.2.4 shows
>>>>>>> differences in the code.
>>>>>>>
>>>>>>> Did we do any change to SlickGrid library that is vendorized? Or is
>>>>>>> just the information in libraries.txt that is incorrect?
>>>>>>> Does anyone know any problem if we bump the version of SlickGrid to
>>>>>>> the newer version after the PR is applied?
>>>>>>>
>>>>>>> Thanks
>>>>>>> Joao
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>
>>
>>
>> --
>> Sent via pgadmin-hackers mailing list ([email protected])
>> To make changes to your subscription:
>> http://www.postgresql.org/mailpref/pgadmin-hackers
>>
>>
>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers
Attachments:
[image/jpeg] Blue_color_SelectAll_issue.jpg (211.6K, 3-Blue_color_SelectAll_issue.jpg)
download | view image
[image/jpeg] Header_text_padding_issue.jpg (232.2K, 4-Header_text_padding_issue.jpg)
download | view image
^ permalink raw reply [nested|flat] 9+ messages in thread
* Re: Issue with SlickGrid
2017-04-26 20:53 Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 06:39 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 06:46 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 11:12 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 12:13 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
2017-04-27 15:49 ` Re: Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 15:53 ` Re: Issue with SlickGrid Dave Page <[email protected]>
2017-05-03 04:26 ` Re: Issue with SlickGrid Murtuza Zabuawala <[email protected]>
@ 2017-05-05 21:44 ` Sarah McAlear <[email protected]>
0 siblings, 0 replies; 9+ messages in thread
From: Sarah McAlear @ 2017-05-05 21:44 UTC (permalink / raw)
To: Murtuza Zabuawala <[email protected]>; +Cc: Dave Page <[email protected]>; pgadmin-hackers; Matthew Kleiman <[email protected]>
Hi Murtuza!
1)
> Individual cell selection is not visible,
> This will be useful to user when user wants to use "By Selection" &
> "Exclude Selection" filter option.
> (Even if active cell is not visible to user, above filters are working
> though when we click on any cell)
Good catch. We'll fix that.
2)
Column header does not look good due bottom padding.
> Refer screenshot.
We think that we actually fixed that with a patch we are currently working
on and will be submitting next week.
3)
Select All color selection issue,
> try running,
> select * from pg_class
> Now scroll horizontally till the last column and again scroll back to
> first column,
> you will see that one of the column gets the blue color as if it is
> selected by user.
> Refer screenshot.
Good catch with this one too! We actually think this is a bug that may have
been introduced before this. We were able to replicate the same issue
without the patch being applied. We're going to take this bug on in our
backlog and include the fix in the upcoming patch we just mentioned.
This only seems to be a bug when the table has more columns than fits on
the viewport. We think we have an idea of how to fix this.
Thanks!
Matt & Sarah
On Wed, May 3, 2017 at 12:26 AM, Murtuza Zabuawala <
[email protected]> wrote:
> Hi Jao,
>
> I found few minor issues,
>
> 1)
> Individual cell selection is not visible,
> This will be useful to user when user wants to use "By Selection" &
> "Exclude Selection" filter option.
> (Even if active cell is not visible to user, above filters are working
> though when we click on any cell)
>
> 2)
> Column header does not look good due bottom padding.
> Refer screenshot.
>
> 3)
> Select All color selection issue,
>
> try running,
> select * from pg_class
>
> Now scroll horizontally till the last column and again scroll back to
> first column,
> you will see that one of the column gets the blue color as if it is
> selected by user.
> Refer screenshot.
>
> Rest of the patch looks good to me.
>
>
> --
> Regards,
> Murtuza Zabuawala
> EnterpriseDB: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
> On Thu, Apr 27, 2017 at 9:23 PM, Dave Page <[email protected]> wrote:
>
>> Thanks Joao. Murtuza, can you review this please?
>>
>> On Thu, Apr 27, 2017 at 4:49 PM, Joao Pedro De Almeida Pereira <
>> [email protected]> wrote:
>>
>>> Hi Hackers,
>>>
>>> We found that the latest version of SlickGrid fixes the scrollbar issue.
>>> We have upgraded it to the latest version in our vendor directory and
>>> updated the tests accordingly in the attached patch.
>>>
>>> We didn't apply any of the custom changes that were previously added.
>>> Please validate that the memory issues that were referenced in the README
>>> file are solved with the latest version of SlickGrid. If we can avoid
>>> changing the code of the libraries that we use, it will be far easier to
>>> continue to upgrade in the future. We will need to upgrade the version of
>>> SlickGrid again soon, once they approve our pull request
>>> <https://github.com/6pac/SlickGrid/pull/100;.
>>>
>>> Thanks,
>>> Joao & Matt
>>>
>>>
>>> On Thu, Apr 27, 2017 at 8:13 AM, Murtuza Zabuawala <
>>> [email protected]> wrote:
>>>
>>>> No, we didn't.
>>>>
>>>> --
>>>> Regards,
>>>> Murtuza Zabuawala
>>>> EnterpriseDB: http://www.enterprisedb.com
>>>> The Enterprise PostgreSQL Company
>>>>
>>>> On Thu, Apr 27, 2017 at 4:42 PM, Joao Pedro De Almeida Pereira <
>>>> [email protected]> wrote:
>>>>
>>>>> Hello Murtuza,
>>>>> Thanks for the explanation. Based on what you said it looks like a bug
>>>>> in the library, have you guys considered sending a PR to it?
>>>>>
>>>>> Thanks
>>>>>
>>>>> On Thu, Apr 27, 2017, 2:46 AM Murtuza Zabuawala <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> +++
>>>>>> Reference: https://www.postgresql.org/message-id/CAKKotZRjqb
>>>>>> KAZev81Zk78nikDVXqLKEDV5r%2BsW8Me31Gpzrm_A%40mail.gmail.com
>>>>>>
>>>>>> --
>>>>>> Regards,
>>>>>> Murtuza Zabuawala
>>>>>> EnterpriseDB: http://www.enterprisedb.com
>>>>>> The Enterprise PostgreSQL Company
>>>>>>
>>>>>> On Thu, Apr 27, 2017 at 12:09 PM, Murtuza Zabuawala <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hello Joao,
>>>>>>>
>>>>>>> Yes, We made some changes in SlickGrid library when we integrated it
>>>>>>> into Query tool.
>>>>>>>
>>>>>>> *Issue:* Last row from the query result set was not displaying
>>>>>>> correctly in query tool when we have scrollbar in grid.
>>>>>>>
>>>>>>> The row hight/width pixel size calculations is done inside SlickGrid
>>>>>>> javascript code, Though we tried solve it through CSS but we had no luck,
>>>>>>> so we had no other choice but to do it in library it self.
>>>>>>>
>>>>>>> The changes were,
>>>>>>> 1) "getDataLengthIncludingAddNew()" function (slick.grid.js) to add
>>>>>>> two new rows instead of one when user add values into row (one row is dummy
>>>>>>> & not visible to user so that it displays last row correctly)
>>>>>>> 2) Other change was done into "appendRowHtml()" function to
>>>>>>> calculating the correct number of rows in SlickGrid result as we have added
>>>>>>> our own custom row as mentioned earlier.
>>>>>>> 3) Abbreviated long CSS classes as mentioed in README file.
>>>>>>>
>>>>>>> Apologies we missed to update this change in README.
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Regards,
>>>>>>> Murtuza Zabuawala
>>>>>>> EnterpriseDB: http://www.enterprisedb.com
>>>>>>> The Enterprise PostgreSQL Company
>>>>>>>
>>>>>>> On Thu, Apr 27, 2017 at 2:23 AM, Joao Pedro De Almeida Pereira <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hello Hackers,
>>>>>>>>
>>>>>>>> While doing some changes to the Query Results we found out that
>>>>>>>> there was a issue with Slick grid.
>>>>>>>>
>>>>>>>> The issue that we found was with the CellSelectModel, behaved
>>>>>>>> differently when pressing Ctrl and Command(Mac). We created a PR
>>>>>>>> <https://github.com/6pac/SlickGrid/pull/100; with the change to
>>>>>>>> changes the behavior of the plugin.
>>>>>>>>
>>>>>>>> When this PR is applied to the SlickGrid library we need to apply
>>>>>>>> it to the current version of SlickGrid that we have vendorized.
>>>>>>>> According to the libraries.txt file we are in version 2.2.4 of the
>>>>>>>> library but a diff between our code and the libraries version 2.2.4 shows
>>>>>>>> differences in the code.
>>>>>>>>
>>>>>>>> Did we do any change to SlickGrid library that is vendorized? Or is
>>>>>>>> just the information in libraries.txt that is incorrect?
>>>>>>>> Does anyone know any problem if we bump the version of SlickGrid to
>>>>>>>> the newer version after the PR is applied?
>>>>>>>>
>>>>>>>> Thanks
>>>>>>>> Joao
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>
>>>
>>>
>>> --
>>> Sent via pgadmin-hackers mailing list ([email protected])
>>> To make changes to your subscription:
>>> http://www.postgresql.org/mailpref/pgadmin-hackers
>>>
>>>
>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EnterpriseDB UK: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>
>
>
> --
> Sent via pgadmin-hackers mailing list ([email protected])
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgadmin-hackers
>
>
^ permalink raw reply [nested|flat] 9+ messages in thread
end of thread, other threads:[~2017-05-05 21:44 UTC | newest]
Thread overview: 9+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2017-04-26 20:53 Issue with SlickGrid Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 06:39 ` Murtuza Zabuawala <[email protected]>
2017-04-27 06:46 ` Murtuza Zabuawala <[email protected]>
2017-04-27 11:12 ` Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 12:13 ` Murtuza Zabuawala <[email protected]>
2017-04-27 15:49 ` Joao Pedro De Almeida Pereira <[email protected]>
2017-04-27 15:53 ` Dave Page <[email protected]>
2017-05-03 04:26 ` Murtuza Zabuawala <[email protected]>
2017-05-05 21:44 ` Sarah McAlear <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox