├── .gitignore
├── .scrutinizer.yml
├── .travis.yml
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE.txt
├── README.md
├── assets
├── css
│ ├── revisr-admin.css
│ └── thickbox.css
├── img
│ ├── loader.gif
│ └── site5.png
├── index.php
├── js
│ ├── revisr-dashboard.js
│ ├── revisr-settings.js
│ ├── revisr-setup.js
│ └── revisr-staging.js
└── lib
│ ├── octicons
│ ├── LICENSE.txt
│ ├── README.md
│ ├── octicons-local.ttf
│ ├── octicons.css
│ ├── octicons.eot
│ ├── octicons.less
│ ├── octicons.svg
│ ├── octicons.ttf
│ ├── octicons.woff
│ └── sprockets-octicons.scss
│ └── select2
│ ├── css
│ ├── select2.css
│ └── select2.min.css
│ └── js
│ ├── i18n
│ ├── az.js
│ ├── bg.js
│ ├── ca.js
│ ├── cs.js
│ ├── da.js
│ ├── de.js
│ ├── en.js
│ ├── es.js
│ ├── et.js
│ ├── eu.js
│ ├── fa.js
│ ├── fi.js
│ ├── fr.js
│ ├── gl.js
│ ├── he.js
│ ├── hi.js
│ ├── hr.js
│ ├── hu.js
│ ├── id.js
│ ├── is.js
│ ├── it.js
│ ├── ko.js
│ ├── lt.js
│ ├── lv.js
│ ├── mk.js
│ ├── nb.js
│ ├── nl.js
│ ├── pl.js
│ ├── pt-BR.js
│ ├── pt.js
│ ├── ro.js
│ ├── ru.js
│ ├── sk.js
│ ├── sr.js
│ ├── sv.js
│ ├── th.js
│ ├── tr.js
│ ├── uk.js
│ ├── vi.js
│ ├── zh-CN.js
│ └── zh-TW.js
│ ├── select2.full.js
│ ├── select2.full.min.js
│ ├── select2.js
│ └── select2.min.js
├── bin
└── install-wp-tests.sh
├── classes
├── class-revisr-activity-table.php
├── class-revisr-admin-pages.php
├── class-revisr-admin.php
├── class-revisr-branch-table.php
├── class-revisr-commits-table.php
├── class-revisr-compatibility.php
├── class-revisr-cron.php
├── class-revisr-db-backup.php
├── class-revisr-db-import.php
├── class-revisr-db.php
├── class-revisr-git-callback.php
├── class-revisr-git.php
├── class-revisr-i18n.php
├── class-revisr-meta-boxes.php
├── class-revisr-process.php
├── class-revisr-remote.php
├── class-revisr-settings-fields.php
├── class-revisr-settings.php
└── index.php
├── index.php
├── languages
├── index.php
└── revisr.pot
├── package.json
├── phpunit.xml
├── readme.txt
├── revisr.php
├── templates
├── index.php
├── pages
│ ├── branches.php
│ ├── commits.php
│ ├── dashboard.php
│ ├── help.php
│ ├── index.php
│ ├── new-commit.php
│ ├── settings.php
│ ├── setup.php
│ └── view-commit.php
└── partials
│ ├── checkout-remote-form.php
│ ├── delete-branch-form.php
│ ├── discard-form.php
│ ├── import-tables-form.php
│ ├── index.php
│ ├── merge-branch-form.php
│ ├── pull-form.php
│ ├── push-form.php
│ └── revert-form.php
├── tests
├── bootstrap.php
├── test-admin.php
├── test-compatibility.php
├── test-db-backup.php
├── test-db-import.php
├── test-db.php
├── test-git.php
├── test-remote.php
└── test-revisr.php
└── uninstall.php
/.gitignore:
--------------------------------------------------------------------------------
1 | # Operating Systems
2 | Thumbs.db
3 | ehthumbs.db
4 | Desktop.ini
5 | $RECYCLE.BIN/
6 | .DS_Store
7 | *~
8 |
9 | # IDEs
10 | *.sublime-project
11 | *.sublime-workspace
12 | .idea
13 | *.pydevproject
14 | .project
15 | .metadata
16 | build/
17 | tmp/
18 | tests/clover.xml
19 |
20 | # Grunt
21 | node_modules
22 |
23 | # Vendor
24 | vendor
25 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | # .scrutinizer.yml
2 | tools:
3 | external_code_coverage: true
4 | sensiolabs_security_checker: true
5 | php_mess_detector: true
6 | php_code_sniffer: true
7 | php_code_coverage: true
8 | php_sim: true
9 | php_analyzer: true
10 | php_pdepend: true
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | sudo: false
4 |
5 | php:
6 | - 5.3
7 | - 5.4
8 | - 5.5
9 |
10 | env:
11 | - WP_VERSION=latest WP_MULTISITE=0
12 | - WP_VERSION=latest WP_MULTISITE=1
13 | - WP_VERSION=4.0 WP_MULTISITE=0
14 | - WP_VERSION=4.0 WP_MULTISITE=1
15 | - WP_VERSION=3.9.2 WP_MULTISITE=0
16 | - WP_VERSION=3.9.2 WP_MULTISITE=1
17 |
18 | before_script:
19 | - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
20 | - cd /tmp/wordpress/
21 | - git init .
22 | - git config user.name "revisr"
23 | - git config user.email "support@expandedfronts.com"
24 | - cd /home/travis/build/ExpandedFronts/Revisr/
25 |
26 | script: phpunit --coverage-clover=coverage.clover
27 |
28 | after_script:
29 | - wget https://scrutinizer-ci.com/ocular.phar
30 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover
31 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | #Contributing to Revisr
2 |
3 | Revisr is open source to encourage feedback and community patches.
4 |
5 | Please check the guidelines below before contributing to make sure that everything stays in order.
6 |
7 | __Please Note:__ GitHub is for bug reports and contributions only - if you have a support question please don't post here, go to the [Support Forum](https://wordpress.org/support/plugin/revisr) instead.
8 |
9 | ## Getting Started
10 |
11 | * Submit a ticket for your issue, assuming one does not already exist.
12 | * Raise it on the [Issue Tracker](https://github.com/expandedfronts/revisr/issues)
13 | * Clearly describe the issue including steps to reproduce the bug.
14 | * Make sure you fill in the earliest version that you know has the issue as well as the version of WordPress you're using.
15 |
16 | ## Making Changes
17 |
18 | * Fork the repository on GitHub
19 | * Make the changes to your forked repository
20 | * Ensure you stick to the [WordPress Coding Standards](https://codex.wordpress.org/WordPress_Coding_Standards)
21 | * When committing, reference your issue (if present) and include a note about the fix
22 | * If possible, and if applicable, please also add/update unit tests for your changes
23 | * Push the changes to your fork and submit a pull request to the 'master' branch of the repository
24 |
25 | ## Code Documentation
26 |
27 | * Please make sure that every function is documented!
28 | * If you're adding/editing a function in a class, make sure to add `@access {private|public|protected}`
29 | * Finally, please use tabs and not spaces. The tab indent size should be 4 for all code.
30 |
31 | Once you've submitted your pull request, it will be reviewed and merged in if all looks good.
32 |
33 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.initConfig({
4 | pkg: grunt.file.readJSON('package.json'),
5 | makepot: {
6 | target: {
7 | options: {
8 | domainPath: '/languages/',
9 | mainFile: 'revisr.php',
10 | potFilename: 'revisr.pot',
11 | potHeaders: {
12 | poedit: true,
13 | 'report-msgid-bugs-to': 'http://wordpress.org/support/plugin/revisr',
14 | 'last-translator': 'Revisr ',
15 | 'language-team': 'Revisr '
16 | },
17 | type: 'wp-plugin',
18 | updateTimestamp: true,
19 | }
20 | }
21 | }
22 | });
23 |
24 | grunt.loadNpmTasks('grunt-wp-i18n');
25 |
26 | };
27 |
--------------------------------------------------------------------------------
/assets/css/revisr-admin.css:
--------------------------------------------------------------------------------
1 | /**
2 | * revisr-admin.css
3 | *
4 | * @package Revisr
5 | * @license GPLv3
6 | * @link https://revisr.io
7 | * @copyright Expanded Fronts, LLC
8 | */
9 |
10 | /*--------------------------------------------------------------
11 | >>> TABLE OF CONTENTS:
12 | ----------------------------------------------------------------
13 | # Dashboard Page
14 | ## Recent Activity
15 | ## "Quick Actions" metabox
16 | ## "Branches/Tags" metabox
17 | # Branches Page
18 | # Commits Pages
19 | ## Committed
20 | ## Staging
21 | # Settings Pages
22 | # Setup
23 | # Misc
24 | --------------------------------------------------------------*/
25 |
26 | /*--------------------------------------------------------------
27 | # Dashboard Page
28 | --------------------------------------------------------------*/
29 | .revisr-poststuff { padding-top: 0 !important; }
30 |
31 | /*--------------------------------------------------------------
32 | ## Recent Activity
33 | --------------------------------------------------------------*/
34 | #revisr-activity-form table th[id=message] { width: 75%; }
35 | #revisr-activity-form .alignleft { display: none; }
36 |
37 | /*--------------------------------------------------------------
38 | ## "Quick Actions" metabox
39 | --------------------------------------------------------------*/
40 | .revisr-quick-action-btn { width: 100%; text-align: left !important; margin-bottom: 4px !important; }
41 | .revisr-quick-action-btn:before { margin: 5px; display: inline-block; float: left; color: #fff; -webkit-font-smoothing: antialiased; }
42 | .revisr-quick-action-btn-txt { float: left; }
43 | #revisr-commit-btn:before { content: "\f132"; margin: 5px 1px !important; font: normal 20px/1 'dashicons'; color: #444; }
44 | #revisr-discard-btn:before { content: "\f158"; margin: 4px 1px !important; font: normal 20px/1 'dashicons'; color: #444; }
45 | #revisr-backup-btn:before { content: "\f096"; font: normal 17px/1 'octicons'; color: #444; }
46 | #revisr-push-btn:before { content: "\f03d"; font: normal 20px/1 'octicons'; color: #444; }
47 | #revisr-pull-btn:before { content: "\f03f"; font: normal 20px/1 'octicons'; color: #444; }
48 | #revisr-loader { float: right; }
49 |
50 | /*--------------------------------------------------------------
51 | ## "Branches/Tags" metabox
52 | --------------------------------------------------------------*/
53 | #revisr-branches-tags-widget #branches { padding: 0; }
54 | #revisr-branches-tags-widget #branches-table { border: 0; }
55 | #revisr-branches-tags-widget #branches-table tr:nth-child(odd) { background-color: #f9f9f9; }
56 | #revisr-manage-branches-link { font-size: 12px; }
57 |
58 | /*--------------------------------------------------------------
59 | # Branches Page
60 | --------------------------------------------------------------*/
61 | .revisr-col-container { margin-top: 25px !important; }
62 | #revisr-branch-form .tablenav.top { display: none; }
63 | #revisr-add-branch-box { max-width: 280px; }
64 | #revisr-add-branch-box h3 { font-size: 14px; padding: 8px 12px; margin: 0; line-height: 1.4; }
65 | #revisr-add-branch-box #add-branch-submit { text-align: center; margin-bottom: 0; padding-bottom: 0; }
66 |
67 | /*--------------------------------------------------------------
68 | # Commits
69 | --------------------------------------------------------------*/
70 | .revisr_page_revisr_commits .alignleft.actions.bulkactions { display: none; }
71 | #revisr-commits-filter #hash, #revisr-commits-filter .column-hash { width:70px !important; }
72 | #revisr-commits-filter .column-title { width: 400px !important; }
73 | #revisr-commits-filter #branch, #revisr-commits-filter #tag, #files_changed, #revisr-commits-filter .column-branch, #revisr-commits-filter .column-tag, .column-files_changed { text-align: center !important; }
74 | .revisr_page_revisr_commits .wrap { margin-top: 27px !important; }
75 |
76 | /*--------------------------------------------------------------
77 | ## Committed
78 | --------------------------------------------------------------*/
79 | #committed { width: 90%; }
80 | .admin_page_revisr_view_commit .wrap { margin-top: 27px !important; }
81 |
82 | /*--------------------------------------------------------------
83 | ## Staging
84 | --------------------------------------------------------------*/
85 | #revisr_save_commit .inside, #revisr_view_commit .inside { padding: 0; }
86 | .revisr-timestamp:before { margin-right: 3px; }
87 | #misc-publishing-actions .revisr-octicon-label:before { color: #888; display: inline-block; font: 400 20px/1 octicons; speak: none; left: -1px; position: relative; top: 0; text-decoration: none!important; vertical-align: top; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
88 | #misc-publishing-actions label[for=revisr-branch]:before { content: '\f020'; padding: 0 7px 0 5px; }
89 | #misc-publishing-actions label[for=revisr-tag]:before { content: '\f015'; padding: 0 5px 0 3px; }
90 | .stage-container { width: 100%; display: inline-block; }
91 | #staged { width: 80%; float: left; overflow-y: scroll; }
92 | #unstaged { width: 80%; float: left; overflow-y: scroll; }
93 | .stage-nav { float: left; margin: 5px; }
94 | .stage-nav-button { margin-top: 7px !important; }
95 | .diff_added { background-color: #cfc; }
96 | .diff_removed { background-color: #fdd; }
97 | .admin_page_revisr_new_commit .wrap { margin-top: 27px !important; }
98 | #revisr-commit-form #title { line-height: normal; }
99 |
100 | /*--------------------------------------------------------------
101 | # Settings
102 | --------------------------------------------------------------*/
103 | .revisr-settings-form { margin-left: 15px; }
104 | #verify-remote { margin-left: 10px; padding: 4px; font-size: 11px; border-radius: 4px; color: #fff; margin-left: 10px; }
105 | .verify-remote-success { background-color: #5cb85c; }
106 | .verify-remote-error { background-color: #AFAFAF; }
107 | #gitignore { width: 35em; }
108 | .revisr-description { width: 35em; }
109 | .revisr-text { width: 35em !important; }
110 | #post-hook-input { width: 35em; }
111 | #revisr-debug-table { max-width: 750px; }
112 | body.revisr_page_revisr_settings #site5_wrapper { margin-right: 20px; }
113 |
114 | /*--------------------------------------------------------------
115 | # Setup
116 | --------------------------------------------------------------*/
117 | #revisr-setup-container { max-width: 400px; background-color: #fff; color: #444; margin: 140px auto 25px; padding: 30px; -webkit-font-smoothing: subpixel-antialiased; -webkit-box-shadow: 0 1px 3px rgba(0,0,0,.13); box-shadow: 0 1px 3px rgba(0,0,0,.13); }
118 | .revisr-setup-input { width: 100% !important; }
119 | .select2-hidden { display:none; }
120 | .revisr-setup-nav { margin-top: 10px; width: 100%; }
121 | .revisr-setup-nav button { width: 48%; }
122 | .revisr-setup-nav:last-child { float: right; }
123 | #revisr-setup-h2 { font-size: 23px; font-weight: 400; padding: 9px 15px 4px 0; line-height: 29px; margin: 0; }
124 |
125 | /*--------------------------------------------------------------
126 | # Misc
127 | --------------------------------------------------------------*/
128 | .revisr-arrow-logo { background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOC4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjI0NS44IDM4MS4xIDgxLjkgODkuNSIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAyNDUuOCAzODEuMSA4MS45IDg5LjUiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iIzQ0NCIgZD0iTTI5NS4yLDM4Ny4yYy01LjEsNS4xLTUuMSwxMy4zLDAsMTguM2MzLjgsMy44LDkuMyw0LjcsMTMuOSwyLjlsNy4yLTcuMmMxLjgtNC43LDAuOS0xMC4yLTIuOS0xMy45DQoJQzMwOC41LDM4Mi4xLDMwMC4zLDM4Mi4xLDI5NS4yLDM4Ny4yeiBNMzA5LjcsNDAxLjZjLTIuOSwyLjktNy42LDIuOS0xMC42LDBjLTIuOS0yLjktMi45LTcuNiwwLTEwLjZjMi45LTIuOSw3LjYtMi45LDEwLjYsMA0KCUMzMTIuNiwzOTQsMzEyLjYsMzk4LjcsMzA5LjcsNDAxLjZ6Ii8+DQo8cGF0aCBmaWxsPSIjNDQ0IiBkPSJNMjY4LjEsNDU0Yy0xMy4yLTEwLjEtMTYuMS0yOS02LjQtNDIuNmM0LTUuNiw5LjQtOS40LDE1LjQtMTEuNGwtMi0xMC4yYy04LjUsMi41LTE2LjIsNy43LTIxLjcsMTUuNQ0KCWMtMTIuOSwxOC4yLTguOSw0My41LDguOCw1N2wtNS42LDguM2wyNS45LTEuMmwtOC42LTIzLjZMMjY4LjEsNDU0eiIvPg0KPHBhdGggZmlsbD0iIzQ0NCIgZD0iTTMxOC4zLDQwMy4zYzEuMS0yLjEsMS43LTQuNSwxLjctN2MwLTguNC02LjgtMTUuMi0xNS4yLTE1LjJzLTE1LjIsNi44LTE1LjIsMTUuMnM2LjgsMTUuMiwxNS4yLDE1LjINCgljMi4xLDAsNC4xLTAuNCw1LjktMS4yYzguNCwxMC42LDkuMiwyNS44LDEsMzcuMmMtMy45LDUuNi05LjQsOS40LTE1LjQsMTEuNGwyLDEwLjJjOC41LTIuNSwxNi4yLTcuNywyMS43LTE1LjUNCglDMzMxLjIsNDM4LjEsMzI5LjksNDE3LjQsMzE4LjMsNDAzLjN6IE0zMDQuOCw0MDMuM2MtMy44LDAtNi45LTMuMS02LjktNi45czMuMS02LjksNi45LTYuOXM2LjksMy4xLDYuOSw2LjkNCglTMzA4LjcsNDAzLjMsMzA0LjgsNDAzLjN6Ii8+DQo8L3N2Zz4=); background-repeat: no-repeat; width: 24px; height: 24px; margin-top: 3px; margin-right: 8px; float: left; }
129 | #site5_wrapper { width: 80px; text-align: center; font-size: 11px; float: right; margin: 0 10px 10px 10px; padding: 0 5px; background-color: #fff; border: 1px solid #ddd; }
130 | #site5_logo { width: 80px; margin-top: -5px; }
131 | .revisr-alert { margin: 20px 0 !important;}
132 |
--------------------------------------------------------------------------------
/assets/css/thickbox.css:
--------------------------------------------------------------------------------
1 | /* Thickbox Styles */
2 | html {
3 | background-color: #fff;
4 | color: #444;
5 | font-family: "Open Sans",sans-serif;
6 | font-size: 14px;
7 | line-height: 1.4em;
8 | }
9 | body {
10 | margin: 0 !important;
11 | overflow: hidden;
12 | }
13 | input[type="text"] {
14 | height: 25px;
15 | font-size: 13px;
16 | }
17 | a {
18 | color: #0074a2 !important;
19 | }
20 | select {
21 | border: 1px solid #ddd;
22 | padding: 2px;
23 | line-height: 28px;
24 | height: 28px;
25 | vertical-align: middle;
26 | font-size: 14px;
27 | background: #fff;
28 | color: #32373c;
29 | outline: 0;
30 | }
31 | .revisr-tb-description {
32 | padding: 10px 15px 10px 15px;
33 | overflow-y: scroll;
34 | height: 155px;
35 | }
36 | .revisr-tb-submit {
37 | width: 100%;
38 | position: fixed;
39 | bottom: 0px;
40 | padding: 15px 0 15px 0;
41 | border-top: 1px solid #ddd;
42 | background-color: #f5f5f5;
43 | text-align: right;
44 | }
45 | .revisr-tb-btn {
46 | height: 30px;
47 | font-size: 14px;
48 | padding: 0 15px;
49 | margin: 0 15px 0 0;
50 | border-radius: 4px;
51 | }
52 | .revisr-tb-btn:hover {
53 | cursor: pointer;
54 | }
55 | .revisr-tb-danger {
56 | background-color:#e14d43;
57 | border:1px #d02c21 solid;
58 | color:#fff;
59 | -webkit-box-shadow: inset 0 1px 0 #ec8b85,0 1px 0 rgba(0,0,0,.15);
60 | box-shadow: inset 0 1px 0 #ec8b85,0 1px 0 rgba(0,0,0,.15);
61 | }
62 | .revisr-tb-danger:hover {
63 | background: #dd382d;
64 | border-color: #ba281e;
65 | color: #fff;
66 | -webkit-box-shadow: inset 0 1px 0 #e8776f;
67 | box-shadow: inset 0 1px 0 #e8776f;
68 | }
69 | .revisr-btn-cancel {
70 | background-color: #f7f7f7;
71 | border: 1px #ccc solid;
72 | color: #555;
73 | }
74 | .revisr-btn-cancel:hover {
75 | background-color: #fafafa;
76 | border: 1px solid #999;
77 | color: #222;
78 | }
79 |
--------------------------------------------------------------------------------
/assets/img/loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expandedfronts/revisr/271228b624042b5fbc509af774bec873a3e2f648/assets/img/loader.gif
--------------------------------------------------------------------------------
/assets/img/site5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/expandedfronts/revisr/271228b624042b5fbc509af774bec873a3e2f648/assets/img/site5.png
--------------------------------------------------------------------------------
/assets/index.php:
--------------------------------------------------------------------------------
1 | ' + revisr_dashboard_vars.login_prompt + '
';
69 | } else {
70 | jQuery('#revisr-loading-alert').hide();
71 | jQuery('#revisr-processing-request').hide();
72 | document.getElementById('revisr-alert-container').innerHTML = response;
73 | }
74 | }
75 | });
76 | }
77 |
78 | /**
79 | * Update the AJAX button counts.
80 | */
81 | function update_counts() {
82 | jQuery.post(ajaxurl, {action: 'ajax_button_count', data: 'unpulled'}, function(response) {
83 | if ( 0 == response ) {
84 | response = '';
85 | }
86 | document.getElementById('revisr-unpulled').innerHTML = response;
87 | });
88 | jQuery.post(ajaxurl, {action: 'ajax_button_count',data: 'unpushed'}, function(response) {
89 | if ( 0 == response ) {
90 | response = '';
91 | }
92 | document.getElementById('revisr-unpushed').innerHTML = response;
93 | });
94 | }
95 |
96 | /**
97 | * Display the loading message.
98 | */
99 | function processing() {
100 | jQuery('.revisr-alert').hide();
101 | jQuery('#revisr-loader').show();
102 | jQuery('#revisr-processing-request').show();
103 | }
104 |
105 | /**
106 | * Run when an AJAX request from the dashboard has been completed.
107 | */
108 | function process_complete() {
109 | jQuery('#revisr-loader').hide();
110 | update_alert();
111 | revisr_list.update();
112 | update_counts();
113 | delayed_refresh();
114 | }
115 |
116 | /**
117 | * Display the branches list.
118 | */
119 | jQuery('#branches-link').click(function() {
120 | jQuery('#tags-tab').attr('class', 'hide-if-no-js');
121 | jQuery('#branches-tab').attr('class', 'tabs');
122 | jQuery('#tags').hide();
123 | jQuery('#branches').show();
124 | });
125 |
126 | /**
127 | * Display the tags list.
128 | */
129 | jQuery('#tags-link').click(function() {
130 | jQuery('#branches-tab').attr('class', 'hide-if-no-js');
131 | jQuery('#tags-tab').attr('class', 'tabs');
132 | jQuery('#branches').hide();
133 | jQuery('#tags').show();
134 | });
135 |
136 | /**
137 | * Redirects to the new commit screen.
138 | */
139 | jQuery('#revisr-commit-btn').click(function() {
140 | window.location = 'admin.php?page=revisr_new_commit';
141 | });
142 |
143 | /**
144 | * Runs when the 'Backup Database' button is clicked.
145 | */
146 | jQuery('#revisr-backup-btn').click(function() {
147 | processing();
148 | jQuery.post(ajaxurl, {action: 'backup_db', source: 'ajax_button', revisr_dashboard_nonce: revisr_dashboard_vars.ajax_nonce}, function(response) {
149 | process_complete();
150 | });
151 | });
152 |
153 |
154 | var revisr_list = {
155 | /**
156 | * Register our triggers
157 | *
158 | * We want to capture clicks on specific links, but also value change in
159 | * the pagination input field. The links contain all the information we
160 | * need concerning the wanted page number or ordering, so we'll just
161 | * parse the URL to extract these variables.
162 | *
163 | * The page number input is trickier: it has no URL so we have to find a
164 | * way around. We'll use the hidden inputs added in TT_Example_List_Table::display()
165 | * to recover the ordering variables, and the default paged input added
166 | * automatically by WordPress.
167 | */
168 | init: function() {
169 | // This will have its utility when dealing with the page number input
170 | var timer;
171 | var delay = 500;
172 | // Pagination links, sortable link
173 | jQuery('.tablenav-pages a, .manage-column.sortable a, .manage-column.sorted a').on('click', function(e) {
174 | // We don't want to actually follow these links
175 | e.preventDefault();
176 | // Simple way: use the URL to extract our needed variables
177 | var query = this.search.substring( 1 );
178 |
179 | var data = {
180 | paged: revisr_list.__query( query, 'paged' ) || '1',
181 | order: revisr_list.__query( query, 'order' ) || 'desc',
182 | orderby: revisr_list.__query( query, 'orderby' ) || 'time',
183 | revisr_event: revisr_list.__query( query, 'revisr_event' ) || 'all',
184 | revisr_user: revisr_list.__query( query, 'revisr_user' ) || 'all',
185 | revisr_time: revisr_list.__query( query, 'revisr_time' ) || 'all'
186 | };
187 | revisr_list.update( data );
188 | });
189 | // Page number input
190 | jQuery('input[name=paged]').on('keyup', function(e) {
191 | // If user hit enter, we don't want to submit the form
192 | // We don't preventDefault() for all keys because it would
193 | // also prevent to get the page number!
194 | if ( 13 == e.which )
195 | e.preventDefault();
196 | // This time we fetch the variables in inputs
197 | var data = {
198 | paged: parseInt( jQuery('input[name=paged]').val() ) || '1',
199 | order: jQuery('input[name=order]').val() || 'asc',
200 | orderby: jQuery('input[name=orderby]').val() || 'title',
201 | revisr_event : jQuery('input[name=revisr_event]').val() || 'all',
202 | revisr_user : jQuery('input[name=revisr_user]').val() || 'all',
203 | revisr_time : jQuery('input[name=revisr_time]').val() || 'all'
204 | };
205 | // Now the timer comes to use: we wait half a second after
206 | // the user stopped typing to actually send the call. If
207 | // we don't, the keyup event will trigger instantly and
208 | // thus may cause duplicate calls before sending the intended
209 | // value
210 | window.clearTimeout( timer );
211 | timer = window.setTimeout(function() {
212 | revisr_list.update( data );
213 | }, delay);
214 | });
215 | },
216 | /**
217 | * AJAX call
218 | *
219 | * Send the call and replace table parts with updated version!
220 | *
221 | * @param object data The data to pass through AJAX
222 | */
223 | update: function( data ) {
224 | jQuery.ajax({
225 | // /wp-admin/admin-ajax.php
226 | url: ajaxurl,
227 | // Add action and nonce to our collected data
228 | data: jQuery.extend(
229 | {
230 | revisr_list_nonce: jQuery('#revisr_list_nonce').val(),
231 | action: 'revisr_get_custom_list',
232 | },
233 | data
234 | ),
235 | // Handle the successful result
236 | success: function( response ) {
237 | // WP_List_Table::ajax_response() returns json
238 | var response = jQuery.parseJSON( response );
239 | // Add the requested rows
240 | if ( response.rows.length )
241 | jQuery('#the-list').html( response.rows );
242 | // Update column headers for sorting
243 | if ( response.column_headers.length )
244 | jQuery('thead tr, tfoot tr').html( response.column_headers );
245 | // Update pagination for navigation
246 | if ( response.pagination.bottom.length )
247 | jQuery('.tablenav.top .tablenav-pages').html( jQuery(response.pagination.top).html() );
248 | if ( response.pagination.top.length )
249 | jQuery('.tablenav.bottom .tablenav-pages').html( jQuery(response.pagination.bottom).html() );
250 | // Init back our event handlers
251 | revisr_list.init();
252 | }
253 | });
254 | },
255 | /**
256 | * Filter the URL Query to extract variables
257 | *
258 | * @see http://css-tricks.com/snippets/javascript/get-url-variables/
259 | *
260 | * @param string query The URL query part containing the variables
261 | * @param string variable Name of the variable we want to get
262 | *
263 | * @return string|boolean The variable value if available, false else.
264 | */
265 | __query: function( query, variable ) {
266 | var vars = query.split("&");
267 | for ( var i = 0; i 1&&(n+="a"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Моля въведете още "+t+" символ";return t>1&&(n+="a"),n},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(e){var t="Можете да направите до "+e.maximum+" ";return e.maximum>1?t+="избора":t+="избор",t},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/ca.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Si us plau, elimina "+t+" car";return t==1?n+="àcter":n+="àcters",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Si us plau, introdueix "+t+" car";return t==1?n+="àcter":n+="àcters",n},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var t="Només es pot seleccionar "+e.maximum+" element";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/cs.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/cs",[],function(){function e(e,t){switch(e){case 2:return t?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím zadejte o jeden znak méně":n<=4?"Prosím zadejte o "+e(n,!0)+" znaky méně":"Prosím zadejte o "+n+" znaků méně"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím zadejte ještě jeden znak":n<=4?"Prosím zadejte ještě další "+e(n,!0)+" znaky":"Prosím zadejte ještě dalších "+n+" znaků"},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(t){var n=t.maximum;return n==1?"Můžete zvolit jen jednu položku":n<=4?"Můžete zvolit maximálně "+e(n,!1)+" položky":"Můžete zvolit maximálně "+n+" položek"},noResults:function(){return"Nenalezeny žádné položky"},searching:function(){return"Vyhledávání…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/da.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Angiv venligst "+t+" tegn mindre";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Angiv venligst "+t+" tegn mere";return n},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var t="Du kan kun vælge "+e.maximum+" emne";return e.maximum!=1&&(t+="r"),t},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/de.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/de",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Bitte "+t+" Zeichen weniger eingeben"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Bitte "+t+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var t="Sie können nur "+e.maximum+" Eintr";return e.maximum===1?t+="ag":t+="äge",t+=" auswählen",t},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/en.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Please delete "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more characters";return n},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var t="You can only select "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/es.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"La carga falló"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor, elimine "+t+" car";return t==1?n+="ácter":n+="acteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Por favor, introduzca "+t+" car";return t==1?n+="ácter":n+="acteres",n},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var t="Sólo puede seleccionar "+e.maximum+" elemento";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/et.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" vähem",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" rohkem",n},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var t="Saad vaid "+e.maximum+" tulemus";return e.maximum==1?t+="e":t+="t",t+=" valida",t},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/eu.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gutxiago",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gehiago",n},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return e.maximum===1?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/fa.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="لطفاً "+t+" کاراکتر را حذف نمایید";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لطفاً تعداد "+t+" کاراکتر یا بیشتر وارد نمایید";return n},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(e){var t="شما تنها میتوانید "+e.maximum+" آیتم را انتخاب نمایید";return t},noResults:function(){return"هیچ نتیجهای یافت نشد"},searching:function(){return"در حال جستجو..."}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/fi.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Ole hyvä ja anna "+t+" merkkiä vähemmän"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Ole hyvä ja anna "+t+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(e){return"Voit valita ainoastaan "+e.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/fr.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Supprimez "+t+" caractère";return t!==1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Saisissez "+t+" caractère";return t!==1&&(n+="s"),n},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){var t="Vous pouvez seulement sélectionner "+e.maximum+" élément";return e.maximum!==1&&(t+="s"),t},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/gl.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/gl",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Engada ";return t===1?n+="un carácter":n+=t+" caracteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Elimine ";return t===1?n+="un carácter":n+=t+" caracteres",n},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){var t="Só pode ";return e.maximum===1?t+="un elemento":t+=e.maximum+" elementos",t},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/he.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"התוצאות לא נטענו בהלכה"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="נא למחוק "+t+" תווים";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="נא להכניס "+t+" תווים או יותר";return n},loadingMore:function(){return"טען תוצאות נוספות…"},maximumSelected:function(e){var t="באפשרותך לבחור רק "+e.maximum+" פריטים";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/hi.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" अक्षर को हटा दें";return t>1&&(n=t+" अक्षरों को हटा दें "),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="कृपया "+t+" या अधिक अक्षर दर्ज करें";return n},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(e){var t="आप केवल "+e.maximum+" आइटम का चयन कर सकते हैं";return t},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/hr.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hr",[],function(){function e(e){var t=" "+e+" znak";return e%10<5&&e%10>0&&(e%100<5||e%100>19)?e%10>1&&(t+="a"):t+="ova",t}return{inputTooLong:function(t){var n=t.input.length-t.maximum;return"Unesite "+e(n)},inputTooShort:function(t){var n=t.minimum-t.input.length;return"Unesite još "+e(n)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(e){return"Maksimalan broj odabranih stavki je "+e.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/hu.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Túl hosszú. "+t+" karakterrel több, mint kellene."},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Túl rövid. Még "+t+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/id.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/id",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Hapuskan "+t+" huruf"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Masukkan "+t+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(e){return"Anda hanya dapat memilih "+e.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/is.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/is",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vinsamlegast styttið texta um "+t+" staf";return t<=1?n:n+"i"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vinsamlegast skrifið "+t+" staf";return t>1&&(n+="i"),n+=" í viðbót",n},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(e){return"Þú getur aðeins valið "+e.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/it.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Per favore cancella "+t+" caratter";return t!==1?n+="i":n+="e",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Per favore inserisci "+t+" o più caratteri";return n},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var t="Puoi selezionare solo "+e.maximum+" element";return e.maximum!==1?t+="i":t+="o",t},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/ko.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/lt.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lt",[],function(){function e(e,t,n,r){return e%100>9&&e%100<21||e%10===0?e%10>1?n:r:t}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Pašalinkite "+n+" simbol";return r+=e(n,"ių","ius","į"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Įrašykite dar "+n+" simbol";return r+=e(n,"ių","ius","į"),r},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(t){var n="Jūs galite pasirinkti tik "+t.maximum+" element";return n+=e(t.maximum,"ų","us","ą"),n},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/lv.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lv",[],function(){function e(e,t,n,r){return e===11?t:e%10===1?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Lūdzu ievadiet par "+n;return r+=" simbol"+e(n,"iem","u","iem"),r+" mazāk"},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Lūdzu ievadiet vēl "+n;return r+=" simbol"+e(n,"us","u","us"),r},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(t){var n="Jūs varat izvēlēties ne vairāk kā "+t.maximum;return n+=" element"+e(t.maximum,"us","u","us"),n},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/mk.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/mk",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Ве молиме внесете "+e.maximum+" помалку карактер";return e.maximum!==1&&(n+="и"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Ве молиме внесете уште "+e.maximum+" карактер";return e.maximum!==1&&(n+="и"),n},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(e){var t="Можете да изберете само "+e.maximum+" ставк";return e.maximum===1?t+="а":t+="и",t},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/nb.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nb",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return"Vennligst fjern "+t+" tegn"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vennligst skriv inn ";return t>1?n+=" flere tegn":n+=" tegn til",n},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/nl.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Gelieve "+t+" karakters te verwijderen";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Gelieve "+t+" of meer karakters in te voeren";return n},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var t="Er kunnen maar "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t+=" worden geselecteerd",t},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/pl.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pl",[],function(){var e=["znak","znaki","znaków"],t=["element","elementy","elementów"],n=function(t,n){if(t===1)return n[0];if(t>1&&t<=4)return n[1];if(t>=5)return n[2]};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Usuń "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Podaj przynajmniej "+r+" "+n(r,e)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(e){return"Możesz zaznaczyć tylko "+e.maximum+" "+n(e.maxiumum,t)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/pt-BR.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Apague "+t+" caracter";return t!=1&&(n+="es"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Digite "+t+" ou mais caracteres";return n},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var t="Você só pode selecionar "+e.maximum+" ite";return e.maximum==1?t+="m":t+="ns",t},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/pt.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor apague "+t+" ";return n+=t!=1?"caracteres":"carácter",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Introduza "+t+" ou mais caracteres";return n},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var t="Apenas pode seleccionar "+e.maximum+" ";return t+=e.maximum!=1?"itens":"item",t},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/ro.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ro",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să introduceți mai puțin de "+t;return n+=" caracter",n!==1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vă rugăm să introduceți incă "+t;return n+=" caracter",n!==1&&(n+="e"),n},loadingMore:function(){return"Se încarcă…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",t!==1&&(t+="e"),t},noResults:function(){return"Nu a fost găsit nimic"},searching:function(){return"Căutare…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/ru.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ru",[],function(){function e(e,t,n,r){return e%10<5&&e%10>0&&e%100<5||e%100>20?e%10>1?n:t:r}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Пожалуйста, введите на "+n+" символ";return r+=e(n,"","a","ов"),r+=" меньше",r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Пожалуйста, введите еще хотя бы "+n+" символ";return r+=e(n,"","a","ов"),r},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(t){var n="Вы можете выбрать не более "+t.maximum+" элемент";return n+=e(t.maximum,"","a","ов"),n},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/sk.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadajte o jeden znak menej":n>=2&&n<=4?"Prosím, zadajte o "+e[n](!0)+" znaky menej":"Prosím, zadajte o "+n+" znakov menej"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadajte ešte jeden znak":n<=4?"Prosím, zadajte ešte ďalšie "+e[n](!0)+" znaky":"Prosím, zadajte ešte ďalších "+n+" znakov"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(t){return t.maximum==1?"Môžete zvoliť len jednu položku":t.maximum>=2&&t.maximum<=4?"Môžete zvoliť najviac "+e[t.maximum](!1)+" položky":"Môžete zvoliť najviac "+t.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/sr.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/sv.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vänligen sudda ut "+t+" tecken";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vänligen skriv in "+t+" eller fler tecken";return n},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(e){var t="Du kan max välja "+e.maximum+" element";return t},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/th.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/th",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="โปรดลบออก "+t+" ตัวอักษร";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="โปรดพิมพ์เพิ่มอีก "+t+" ตัวอักษร";return n},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(e){var t="คุณสามารถเลือกได้ไม่เกิน "+e.maximum+" รายการ";return t},noResults:function(){return"ม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/tr.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/tr",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" karakter daha girmelisiniz";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="En az "+t+" karakter daha girmelisiniz";return n},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(e){var t="Sadece "+e.maximum+" seçim yapabilirsiniz";return t},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/uk.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/uk",[],function(){function e(e,t,n,r){return e%100>10&&e%100<15?r:e%10===1?t:e%10>1&&e%10<5?n:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Будь ласка, видаліть "+n+" "+e(t.maximum,"літеру","літери","літер")},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Будь ласка, введіть "+t+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(t){return"Ви можете вибрати лише "+t.maximum+" "+e(t.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/vi.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/vi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vui lòng nhập ít hơn "+t+" ký tự";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vui lòng nhập nhiều hơn "+t+' ký tự"';return n},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(e){var t="Chỉ có thể chọn được "+e.maximum+" lựa chọn";return t},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/zh-CN.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";return n},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"个项目";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/assets/lib/select2/js/i18n/zh-TW.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.0 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="請刪掉"+t+"個字元";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="請再輸入"+t+"個字元";return n},loadingMore:function(){return"載入中…"},maximumSelected:function(e){var t="你只能選擇最多"+e.maximum+"項";return t},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/bin/install-wp-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [ $# -lt 3 ]; then
4 | echo "usage: $0 [db-host] [wp-version]"
5 | exit 1
6 | fi
7 |
8 | DB_NAME=$1
9 | DB_USER=$2
10 | DB_PASS=$3
11 | DB_HOST=${4-localhost}
12 | WP_VERSION=${5-latest}
13 |
14 | WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib}
15 | WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/}
16 |
17 | download() {
18 | if [ `which curl` ]; then
19 | curl -s "$1" > "$2";
20 | elif [ `which wget` ]; then
21 | wget -nv -O "$2" "$1"
22 | fi
23 | }
24 |
25 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then
26 | WP_TESTS_TAG="tags/$WP_VERSION"
27 | else
28 | # http serves a single offer, whereas https serves multiple. we only want one
29 | download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
30 | grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
31 | LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
32 | if [[ -z "$LATEST_VERSION" ]]; then
33 | echo "Latest WordPress version could not be found"
34 | exit 1
35 | fi
36 | WP_TESTS_TAG="tags/$LATEST_VERSION"
37 | fi
38 |
39 | set -ex
40 |
41 | install_wp() {
42 |
43 | if [ -d $WP_CORE_DIR ]; then
44 | return;
45 | fi
46 |
47 | mkdir -p $WP_CORE_DIR
48 |
49 | if [ $WP_VERSION == 'latest' ]; then
50 | local ARCHIVE_NAME='latest'
51 | else
52 | local ARCHIVE_NAME="wordpress-$WP_VERSION"
53 | fi
54 |
55 | download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz
56 | tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR
57 |
58 | download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
59 | }
60 |
61 | install_test_suite() {
62 | # portable in-place argument for both GNU sed and Mac OSX sed
63 | if [[ $(uname -s) == 'Darwin' ]]; then
64 | local ioption='-i .bak'
65 | else
66 | local ioption='-i'
67 | fi
68 |
69 | # set up testing suite if it doesn't yet exist
70 | if [ ! -d $WP_TESTS_DIR ]; then
71 | # set up testing suite
72 | mkdir -p $WP_TESTS_DIR
73 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
74 | fi
75 |
76 | cd $WP_TESTS_DIR
77 |
78 | if [ ! -f wp-tests-config.php ]; then
79 | download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
80 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php
81 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
82 | sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
83 | sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
84 | sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
85 | fi
86 |
87 | }
88 |
89 | install_db() {
90 | # parse DB_HOST for port or socket references
91 | local PARTS=(${DB_HOST//\:/ })
92 | local DB_HOSTNAME=${PARTS[0]};
93 | local DB_SOCK_OR_PORT=${PARTS[1]};
94 | local EXTRA=""
95 |
96 | if ! [ -z $DB_HOSTNAME ] ; then
97 | if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
98 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
99 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then
100 | EXTRA=" --socket=$DB_SOCK_OR_PORT"
101 | elif ! [ -z $DB_HOSTNAME ] ; then
102 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
103 | fi
104 | fi
105 |
106 | # create database
107 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
108 | }
109 |
110 | install_wp
111 | install_test_suite
112 | install_db
113 |
--------------------------------------------------------------------------------
/classes/class-revisr-admin.php:
--------------------------------------------------------------------------------
1 | Click here for more details, or try again.', 'revisr' ), $error_url );
35 | }
36 |
37 | set_transient( 'revisr_error', $message, 10 );
38 |
39 | } else {
40 | set_transient( 'revisr_alert', $message, 3 );
41 | }
42 | }
43 |
44 | /**
45 | * Returns the data for the AJAX buttons.
46 | * @access public
47 | */
48 | public function ajax_button_count() {
49 | if ( $_REQUEST['data'] == 'unpulled' ) {
50 | echo revisr()->git->count_unpulled();
51 | } else {
52 | echo revisr()->git->count_unpushed();
53 | }
54 | exit();
55 | }
56 |
57 | /**
58 | * Deletes existing transients.
59 | * @access public
60 | */
61 | public static function clear_transients( $errors = true ) {
62 | if ( true === $errors ) {
63 | delete_transient( 'revisr_error' );
64 | delete_transient( 'revisr_error_details' );
65 | } else {
66 | delete_transient( 'revisr_alert' );
67 | }
68 | }
69 |
70 | /**
71 | * Helper function for determining if we're in setup mode.
72 | * @access public
73 | * @return boolean
74 | */
75 | public static function is_doing_setup() {
76 |
77 | if ( revisr()->git->is_repo ) {
78 | return false;
79 | } else {
80 | if ( defined( 'REVISR_SKIP_SETUP' ) || get_transient( 'revisr_skip_setup' ) ) {
81 | return false;
82 | }
83 | return true;
84 | }
85 |
86 | }
87 |
88 | /**
89 | * Escapes a shell arguement.
90 | * @access public
91 | * @param string $string The string to escape.
92 | * @return string $string The escaped string.
93 | */
94 | public static function escapeshellarg( $string ) {
95 | $os = Revisr_Compatibility::get_os();
96 | if ( 'WIN' !== $os['code'] ) {
97 | return escapeshellarg( $string );
98 | } else {
99 | // Windows-friendly workaround.
100 | return '"' . str_replace( "'", "'\\''", $string ) . '"';
101 | }
102 | }
103 |
104 | /**
105 | * Logs an event to the database.
106 | * @access public
107 | * @param string $message The message to show in the Recent Activity.
108 | * @param string $event Will be used for filtering later.
109 | * @param string $user An optional user to associate the record with.
110 | */
111 | public static function log( $message, $event, $user = '' ) {
112 |
113 | global $wpdb;
114 |
115 | $time = current_time( 'mysql' );
116 | $table = Revisr::get_table_name();
117 |
118 | if ( '' === $user ) {
119 | $user = wp_get_current_user();
120 | $username = $user->user_login;
121 | } else {
122 | $username = $user;
123 | }
124 |
125 | if ( ! $username || '' === $username ) {
126 | $username = __( 'Revisr Bot', 'revisr' );
127 | }
128 |
129 | $wpdb->insert(
130 | "$table",
131 | array(
132 | 'time' => $time,
133 | 'message' => $message,
134 | 'event' => $event,
135 | 'user' => $username,
136 | ),
137 | array(
138 | '%s',
139 | '%s',
140 | '%s',
141 | '%s',
142 | )
143 | );
144 | }
145 |
146 | /**
147 | * Notifies the admin if notifications are enabled.
148 | * @access private
149 | * @param string $subject The subject line of the email.
150 | * @param string $message The message for the email.
151 | */
152 | public static function notify( $subject, $message ) {
153 | $options = Revisr::get_options();
154 | $url = get_admin_url() . 'admin.php?page=revisr';
155 |
156 | if ( isset( $options['notifications'] ) ) {
157 | $email = $options['email'];
158 | $message .= ' ';
159 | $message .= sprintf( __( 'Click here for more details.', 'revisr' ), $url );
160 | $headers = "Content-Type: text/html; charset=ISO-8859-1\r\n";
161 | wp_mail( $email, $subject, $message, $headers );
162 | }
163 | }
164 |
165 | /**
166 | * Renders an alert and removes the old data.
167 | * @access public
168 | * @param boolean $errors_only Whether or not to only display errors.
169 | */
170 | public static function render_alert( $errors_only = false ) {
171 | $alert = get_transient( 'revisr_alert' );
172 | $error = get_transient( 'revisr_error' );
173 |
174 | if ( $error ) {
175 | $alert = '' . wpautop( $error ) . '
';
176 | } else if ( $alert ) {
177 | $alert = '' . wpautop( $alert ) . '
';
178 | } else {
179 | if ( revisr()->git->count_untracked() == '0' ) {
180 | $msg = sprintf( __( 'There are currently no untracked files on branch %s.', 'revisr' ), revisr()->git->branch );
181 | $alert = '';
182 | } else {
183 | $link = get_admin_url() . 'admin.php?page=revisr_new_commit';
184 | $msg = sprintf( __( 'There are currently %d untracked files on branch %s. Commit your changes to save them.', 'revisr' ), revisr()->git->count_untracked(), revisr()->git->branch, $link );
185 | $alert = '';
186 | }
187 | }
188 |
189 | if ( $errors_only && false !== $error ) {
190 | echo $alert;
191 | } else if ( ! $errors_only ) {
192 | echo $alert;
193 | }
194 |
195 | if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
196 | exit();
197 | }
198 |
199 | }
200 |
201 | /**
202 | * Updates user settings to be compatible with 1.8.
203 | * @access public
204 | */
205 | public function do_upgrade() {
206 | global $wpdb;
207 |
208 | // For users upgrading from 1.7 and older.
209 | if ( get_option( 'revisr_db_version' ) === '1.0' ) {
210 |
211 | // Check for the "auto_push" option and save it to the config.
212 | if ( isset( revisr()->options['auto_push'] ) ) {
213 | revisr()->git->set_config( 'revisr', 'auto-push', 'true' );
214 | }
215 |
216 | // Check for the "auto_pull" option and save it to the config.
217 | if ( isset( revisr()->options['auto_pull'] ) ) {
218 | revisr()->git->set_config( 'revisr', 'auto-pull', 'true' );
219 | }
220 |
221 | // Check for the "reset_db" option and save it to the config.
222 | if ( isset( revisr()->options['reset_db'] ) ) {
223 | revisr()->git->set_config( 'revisr', 'import-checkouts', 'true' );
224 | }
225 |
226 | // Check for the "mysql_path" option and save it to the config.
227 | if ( isset( revisr()->options['mysql_path'] ) ) {
228 | revisr()->git->set_config( 'revisr', 'mysql-path', revisr()->options['mysql_path'] );
229 | }
230 |
231 | // Configure the database tracking to use all tables, as this was how it behaved in 1.7.
232 | revisr()->git->set_config( 'revisr', 'db_tracking', 'all_tables' );
233 | }
234 |
235 | // Upgrades from the "revisr_commits" custom post type to pure Git.
236 | $table = Revisr::get_table_name();
237 | $commits = $wpdb->get_results( "SELECT * FROM $table WHERE event = 'commit'", ARRAY_A );
238 |
239 | if ( is_array( $commits ) && ! empty( $commits ) ) {
240 |
241 | foreach ( $commits as $commit ) {
242 | // Get the commit short hash from the message.
243 | $msg_array = explode( '#', $commit['message'] );
244 | $commit_id = substr( $msg_array[1], 0, 7 );
245 |
246 | // Prepare the new message.
247 | $new_msg = sprintf(
248 | __( 'Committed #%s to the local repository.', 'revisr' ),
249 | get_admin_url() . 'admin.php?page=revisr_view_commit&commit=' . $commit_id,
250 | $commit_id
251 | );
252 |
253 | // Update the existing message.
254 | $query = $wpdb->prepare(
255 | "UPDATE $table SET message = %s WHERE id = '%d'",
256 | $new_msg,
257 | $commit['id']
258 | );
259 |
260 | $wpdb->query( $query );
261 | }
262 |
263 | }
264 |
265 | // Update the database schema using dbDelta.
266 | Revisr::install();
267 |
268 | }
269 |
270 | /**
271 | * Helper function for writing to the wp-config.php file,
272 | * taken from WP Super Cache.
273 | *
274 | * @access public
275 | * @return boolean
276 | */
277 | public static function replace_config_line( $old, $new, $file = '' ) {
278 |
279 | if ( $file === '' ) {
280 | if ( file_exists( ABSPATH . 'wp-config.php') ) {
281 | $file = ABSPATH . 'wp-config.php';
282 | } else {
283 | $file = dirname(ABSPATH) . '/wp-config.php';
284 | }
285 | }
286 |
287 | if ( @is_file( $file ) == false ) {
288 | return false;
289 | }
290 | if (!is_writeable( $file ) ) {
291 | return false;
292 | }
293 |
294 | $found = false;
295 | $lines = file($file);
296 | foreach( (array)$lines as $line ) {
297 | if ( preg_match("/$old/", $line)) {
298 | $found = true;
299 | break;
300 | }
301 | }
302 | if ($found) {
303 | $fd = fopen($file, 'w');
304 | foreach( (array)$lines as $line ) {
305 | if ( !preg_match("/$old/", $line))
306 | fputs($fd, $line);
307 | else {
308 | fputs($fd, "$new // Added by Revisr\n");
309 | }
310 | }
311 | fclose($fd);
312 | return true;
313 | }
314 | $fd = fopen($file, 'w');
315 | $done = false;
316 | foreach( (array)$lines as $line ) {
317 | if ( $done || !preg_match('/^(if\ \(\ \!\ )?define|\$|\?>/', $line) ) {
318 | fputs($fd, $line);
319 | } else {
320 | fputs($fd, "$new // Added by Revisr\n");
321 | fputs($fd, $line);
322 | $done = true;
323 | }
324 | }
325 | fclose($fd);
326 | return true;
327 |
328 | }
329 |
330 | /**
331 | * Wrapper for wp_verify_nonce.
332 | *
333 | * @access public
334 | */
335 | public static function verify_nonce( $nonce, $action ) {
336 |
337 | if ( ! wp_verify_nonce( $nonce, $action ) ) {
338 | wp_die( __( 'Cheatin’ uh?', 'revisr' ) );
339 | }
340 |
341 | }
342 |
343 | /**
344 | * Helper function for processing redirects.
345 | *
346 | * @access public
347 | * @param string $url The URL to redirect to.
348 | * @param bool $echo Set to true if the redirect should be done in Javascript.
349 | */
350 | public static function redirect( $url = '', $echo = false ) {
351 |
352 | if ( '' === $url ) {
353 | $url = get_admin_url() . 'admin.php?page=revisr';
354 | }
355 |
356 | if ( $echo || isset( $_REQUEST['echo_redirect'] ) ) {
357 | _e( 'Processing...', 'revisr' );
358 | ?>
359 |
362 | 'branch',
42 | 'plural' => 'branches'
43 | ) );
44 |
45 | add_screen_option(
46 | 'per_page',
47 | array(
48 | 'default' => 10,
49 | 'label' => __( 'Branches per page', 'revisr' ),
50 | 'option' => 'edit_revisr_branches_per_page',
51 | )
52 | );
53 |
54 | set_screen_options();
55 | }
56 |
57 | /**
58 | * Sets the screen options for the Revisr branches page.
59 | * @access public
60 | * @param boolean $status This seems to be false
61 | * @param string $option The name of the option
62 | * @param int $value The number of events to display
63 | * @return int|boolean
64 | */
65 | public function set_screen_option( $status, $option, $value ) {
66 | if ( 'edit_revisr_branches_per_page' === $option ) {
67 | return $value;
68 | }
69 | return $status;
70 | }
71 |
72 | /**
73 | * Returns an array of the column names.
74 | * @access public
75 | * @return array
76 | */
77 | public function get_columns() {
78 | $columns = array(
79 | 'branch' => __( 'Branch', 'revisr' ),
80 | 'updated' => __( 'Last Updated', 'revisr' ),
81 | 'actions' => __( 'Actions', 'revisr' ),
82 | );
83 | return $columns;
84 | }
85 |
86 | /**
87 | * Returns an array of columns that are sortable.
88 | * @access public
89 | * @return array
90 | */
91 | public function get_sortable_columns() {
92 | $sortable_columns = array(
93 | 'branch' => array( 'branch', false ),
94 | 'updated' => array( 'updated', false )
95 | );
96 | return $sortable_columns;
97 | }
98 |
99 | /**
100 | * Returns an array containing the branch information.
101 | * @access public
102 | * @return array
103 | */
104 | public function get_data() {
105 |
106 | // Basic filter for viewing remote branches.
107 | if ( isset( $_GET['branches'] ) && $_GET['branches'] === 'remote' ) {
108 | // We may need to clear out the cache for the remote branches.
109 | revisr()->git->run( 'remote', array( 'update', '--prune' ) );
110 | $remote = true;
111 | } else {
112 | $remote = false;
113 | }
114 |
115 | // Get the branches.
116 | $branches = revisr()->git->get_branches( $remote );
117 | $branches_array = array();
118 |
119 | if ( is_array( $branches ) && ! empty( $branches ) ) {
120 |
121 | $count = 0;
122 |
123 | foreach ( $branches as $key => $value ) {
124 |
125 | $branch = substr( $value, 2 );
126 | $updated = revisr()->git->get_branch_last_updated( $branch );
127 |
128 | if ( substr( $value, 0, 1 ) === '*' ) {
129 | $current = true;
130 | $branch_title = sprintf( '%s %s ', $branch, __( '(current branch)', 'revisr' ) );
131 | } else {
132 | $current = false;
133 | $branch_title = $branch;
134 | }
135 |
136 | $branches_array[$count]['branch'] = $branch_title;
137 | $branches_array[$count]['updated'] = $updated;
138 | $branches_array[$count]['actions'] = $this->get_actions( $branch, $remote, $current );
139 |
140 | $count++;
141 |
142 | }
143 |
144 | }
145 |
146 | return $branches_array;
147 | }
148 |
149 | /**
150 | * Returns possible actions for a given branch.
151 | * @access public
152 | * @return string
153 | */
154 | public function get_actions( $branch, $remote, $current ) {
155 |
156 | $admin_url = get_admin_url();
157 | $checkout_text = __( 'Checkout', 'revisr' );
158 | $merge_text = __( 'Merge', 'revisr' );
159 | $delete_text = __( 'Delete', 'revisr' );
160 | $checkout_title = __( 'Checkout Branch', 'revisr' );
161 | $merge_title = __( 'Merge Branch', 'revisr' );
162 | $delete_title = __( 'Delete Branch', 'revisr' );
163 | $checkout_url = wp_nonce_url( $admin_url . "admin-post.php?action=process_checkout&branch=" . $branch, 'process_checkout', 'revisr_checkout_nonce' );
164 | $merge_url = $admin_url . "admin-post.php?action=revisr_merge_branch_form&branch=" . $branch . "&TB_iframe=true&width=400&height=225";
165 | $delete_url = $admin_url . "admin-post.php?action=revisr_delete_branch_form&branch=" . $branch . "&TB_iframe=true&width=400&height=225";
166 |
167 | if ( $current ) {
168 | return sprintf(
169 | '%s
170 | %s
171 | %s ',
172 | $checkout_text,
173 | $merge_text,
174 | $delete_text
175 | );
176 | }
177 |
178 | if ( ! $remote ) {
179 |
180 | return sprintf(
181 | '%s
182 | %s
183 | %s ',
184 | $checkout_url,
185 | $checkout_text,
186 | $merge_url,
187 | $merge_title,
188 | $merge_text,
189 | $delete_url,
190 | $delete_title,
191 | $delete_text
192 | );
193 |
194 | } else {
195 | $checkout_url = esc_url( $admin_url . 'admin-post.php?action=revisr_checkout_remote_form&branch=' . $branch . '&TB_iframe=true&width=400&height=225' );
196 | $merge_url = esc_url( $admin_url . 'admin-post.php?action=revisr_merge_branch_form&branch=' . $branch . '&TB_iframe=true&width=400&height=225' );
197 | $delete_url = esc_url( $admin_url . 'admin-post.php?action=revisr_delete_branch_form&branch=' . $branch . '&remote=true&TB_iframe=true&width=400&height=225' );
198 |
199 | return sprintf(
200 | '%s
201 | %s
202 | %s ',
203 | $checkout_url,
204 | $checkout_title,
205 | $checkout_text,
206 | $merge_url,
207 | $merge_title,
208 | $merge_text,
209 | $delete_url,
210 | $delete_title,
211 | $delete_text
212 | );
213 | }
214 |
215 | }
216 |
217 | /**
218 | * Renders the default data for a column.
219 | * @access public
220 | * @param array $item A singular item (one full row's worth of data)
221 | * @param array $column_name The name/slug of the column to be processed
222 | * @return string
223 | */
224 | public function column_default( $item, $column_name ) {
225 | return $item[$column_name];
226 | }
227 |
228 | /**
229 | * Called when no branches are found.
230 | * @access public
231 | */
232 | public function no_items() {
233 | _e( 'No branches found.', 'revisr' );
234 | }
235 |
236 | /**
237 | * Prepares the data for display.
238 | * @access public
239 | */
240 | public function prepare_items() {
241 | global $wpdb;
242 |
243 | // Number of items per page.
244 | $per_page = $this->get_items_per_page( 'edit_revisr_branches_per_page', 10 );
245 |
246 | // Set up the custom columns.
247 | $columns = $this->get_columns();
248 | $hidden = array();
249 | $sortable = $this->get_sortable_columns();
250 |
251 | // Builds the list of column headers.
252 | $this->_column_headers = array( $columns, $hidden, $sortable );
253 |
254 | // Get the data to populate into the table.
255 | $data = $this->get_data();
256 |
257 | // Handle sorting of the data.
258 | function usort_reorder($a,$b){
259 | $orderby = ( ! empty( $_REQUEST['orderby'] ) ) ? $_REQUEST['orderby'] : 'branch'; //If no sort, default to time.
260 | $order = ( ! empty( $_REQUEST['order'] ) ) ? $_REQUEST['order'] : 'desc'; //If no order, default to desc
261 | $result = strcmp($a[$orderby], $b[$orderby]); //Determine sort order
262 | return ( $order==='asc' ) ? $result : -$result; //Send final sort direction to usort
263 | }
264 | usort( $data, 'usort_reorder' );
265 |
266 | // Pagination.
267 | $current_page = $this->get_pagenum();
268 | $total_items = count($data);
269 | $data = array_slice($data,(($current_page-1)*$per_page),$per_page);
270 |
271 | $this->items = $data;
272 | $this->set_pagination_args( array(
273 | 'total_items' => $total_items,
274 | 'per_page' => $per_page,
275 | 'total_pages' => ceil($total_items/$per_page),
276 | 'orderby' => ! empty( $_REQUEST['orderby'] ) && '' != $_REQUEST['orderby'] ? $_REQUEST['orderby'] : 'time',
277 | 'order' => ! empty( $_REQUEST['order'] ) && '' != $_REQUEST['order'] ? $_REQUEST['order'] : 'desc'
278 | ) );
279 | }
280 |
281 | /**
282 | * Displays the table.
283 | * @access public
284 | */
285 | public function display() {
286 | wp_nonce_field( 'revisr-branches-nonce', 'revisr_branches_nonce' );
287 |
288 | echo ' ';
289 | echo ' ';
290 |
291 | parent::display();
292 | }
293 |
294 | /**
295 | * Extra table navigation.
296 | * @access public
297 | * @param string $which
298 | * @return string
299 | */
300 | public function extra_tablenav( $which ) {
301 | if ( 'top' != $which && revisr()->git->has_remote() ) {
302 |
303 | if ( isset( $_GET['branches'] ) && $_GET['branches'] == 'remote' ) {
304 | $url = esc_url( add_query_arg( array( 'branches' => 'local' ) ) );
305 | printf( '%s ', $url, __( 'Local Branches', 'revisr' ) );
306 |
307 | } else {
308 | $url = esc_url( add_query_arg( array( 'branches' => 'remote' ) ) );
309 | printf( '%s ', $url, __( 'Remote Branches', 'revisr' ) );
310 | }
311 |
312 | }
313 | }
314 |
315 | }
316 |
--------------------------------------------------------------------------------
/classes/class-revisr-compatibility.php:
--------------------------------------------------------------------------------
1 | prefix ) . "\n";
37 | $return .= 'WP_DEBUG: ' . ( defined( 'WP_DEBUG' ) ? WP_DEBUG ? 'Enabled' : 'Disabled' : 'Not set' ) . "\n";
38 | $return .= 'Memory Limit: ' . WP_MEMORY_LIMIT . "\n";
39 |
40 | // Revisr Configuration
41 | $return .= "\n" . '-- Revisr Configuration' . "\n\n";
42 | $return .= 'Plugin Version: ' . REVISR_VERSION . "\n";
43 |
44 | if ( isset( revisr()->options['automatic_backups'] ) && 'none' !== revisr()->options['automatic_backups'] ) {
45 | $backups = 'Enabled';
46 | } else {
47 | $backups = 'Disabled';
48 | }
49 | $return .= 'Automatic Backups: ' . $backups . "\n";
50 |
51 | if ( revisr()->git->get_config( 'revisr', 'auto-push' ) === 'true' ) {
52 | $auto_push = 'Enabled';
53 | } else {
54 | $auto_push = 'Disabled';
55 | }
56 | $return .= 'Auto-Push: ' . $auto_push . "\n";
57 |
58 | if ( revisr()->git->get_config( 'revisr', 'auto-pull' ) === 'true' ) {
59 | $auto_pull = 'Enabled';
60 | } else {
61 | $auto_pull = 'Disabled';
62 | }
63 | $return .= 'Auto-Pull: ' . $auto_pull . "\n";
64 |
65 | if ( revisr()->git->get_config( 'revisr', 'import-checkouts' ) === 'true' ) {
66 | $import_checkouts = 'Enabled';
67 | } else {
68 | $import_checkouts = 'Disabled';
69 | }
70 | $return .= 'Import checkouts: ' . $import_checkouts . "\n";
71 |
72 | if ( revisr()->git->get_config( 'revisr', 'import-pulls' ) === 'true' ) {
73 | $import_pulls = 'Enabled';
74 | } else {
75 | $import_pulls = 'Disabled';
76 | }
77 | $return .= 'Import pulls: ' . $import_pulls . "\n";
78 | $return .= 'Work Tree: ' . revisr()->git->get_work_tree() . "\n";
79 | $return .= 'Git Dir: ' . revisr()->git->get_git_dir() . "\n";
80 |
81 | if ( revisr()->git->is_repo ) {
82 | $detected = 'true';
83 | } else {
84 | $detected = 'false';
85 | }
86 | $return .= 'Repository Detected: ' . $detected . "\n";
87 | if ( 'true' === $detected ) {
88 | $return .= 'Repository Writable: ' . Revisr_Compatibility::server_has_permissions( revisr()->git->get_git_dir() ) . "\n";
89 | }
90 |
91 |
92 | // Server Configuration
93 | $return .= "\n" . '-- Server Configuration' . "\n\n";
94 | $os = Revisr_Compatibility::get_os();
95 | $return .= 'Operating System: ' . $os['name'] . "\n";
96 | $return .= 'PHP Version: ' . PHP_VERSION . "\n";
97 | $return .= 'MySQL Version: ' . $wpdb->db_version() . "\n";
98 | $return .= 'Git Version: ' . revisr()->git->version() . "\n";
99 |
100 | $return .= 'Git Install Path: ' . Revisr_Compatibility::guess_path( 'git' ) . "\n";
101 | $return .= 'MySQL Install Path: ' . Revisr_Compatibility::guess_path( 'mysql' ) . "\n";
102 |
103 | $return .= 'Server Software: ' . $_SERVER['SERVER_SOFTWARE'] . "\n";
104 | $return .= 'Server User: ' . Revisr_Compatibility::get_user() . "\n";
105 |
106 | // PHP configs... now we're getting to the important stuff
107 | $return .= "\n" . '-- PHP Configuration' . "\n\n";
108 | $return .= 'Safe Mode: ' . ( ini_get( 'safe_mode' ) ? 'Enabled' : 'Disabled' . "\n" );
109 |
110 | if ( function_exists( 'exec' ) ) {
111 | $exec = 'Enabled';
112 | } else {
113 | $exec = 'Disabled';
114 | }
115 |
116 | $return .= 'Exec Enabled: ' . $exec . "\n";
117 | $return .= 'Memory Limit: ' . ini_get( 'memory_limit' ) . "\n";
118 | $return .= 'Upload Max Size: ' . ini_get( 'upload_max_filesize' ) . "\n";
119 | $return .= 'Post Max Size: ' . ini_get( 'post_max_size' ) . "\n";
120 | $return .= 'Upload Max Filesize: ' . ini_get( 'upload_max_filesize' ) . "\n";
121 | $return .= 'Time Limit: ' . ini_get( 'max_execution_time' ) . "\n";
122 | $return .= 'Max Input Vars: ' . ini_get( 'max_input_vars' ) . "\n";
123 | $return .= 'Display Errors: ' . ( ini_get( 'display_errors' ) ? 'On (' . ini_get( 'display_errors' ) . ')' : 'N/A' ) . "\n";
124 |
125 | // WordPress active plugins
126 | $return .= "\n" . '-- WordPress Active Plugins' . "\n\n";
127 | $plugins = get_plugins();
128 | $active_plugins = get_option( 'active_plugins', array() );
129 | foreach( $plugins as $plugin_path => $plugin ) {
130 | if( !in_array( $plugin_path, $active_plugins ) )
131 | continue;
132 | $return .= $plugin['Name'] . ': ' . $plugin['Version'] . "\n";
133 | }
134 |
135 | // WordPress inactive plugins
136 | $return .= "\n" . '-- WordPress Inactive Plugins' . "\n\n";
137 | foreach( $plugins as $plugin_path => $plugin ) {
138 | if( in_array( $plugin_path, $active_plugins ) )
139 | continue;
140 | $return .= $plugin['Name'] . ': ' . $plugin['Version'] . "\n";
141 | }
142 |
143 | if( is_multisite() ) {
144 | // WordPress Multisite active plugins
145 | $return .= "\n" . '-- Network Active Plugins' . "\n\n";
146 | $plugins = wp_get_active_network_plugins();
147 | $active_plugins = get_site_option( 'active_sitewide_plugins', array() );
148 | foreach( $plugins as $plugin_path ) {
149 | $plugin_base = plugin_basename( $plugin_path );
150 | if( !array_key_exists( $plugin_base, $active_plugins ) )
151 | continue;
152 | $plugin = get_plugin_data( $plugin_path );
153 | $return .= $plugin['Name'] . ': ' . $plugin['Version'] . "\n";
154 | }
155 | }
156 |
157 | $return .= "\n" . '### End System Info ###';
158 | return $return;
159 | }
160 |
161 | /**
162 | * Determines the current operating system.
163 | * @access public
164 | * @return array
165 | */
166 | public static function get_os() {
167 | $os = array();
168 | $uname = php_uname( 's' );
169 | $os['code'] = strtoupper( substr( $uname, 0, 3 ) );
170 | $os['name'] = $uname;
171 | return $os;
172 | }
173 |
174 | /**
175 | * Gets the user running this PHP process.
176 | * @access public
177 | * @return string
178 | */
179 | public static function get_user() {
180 | if ( function_exists( 'exec' ) ) {
181 | return exec( 'whoami' );
182 | }
183 | return __( 'Unknown', 'revisr' );
184 | }
185 |
186 | /**
187 | * Tries to guess the install path to the provided program.
188 | * @access public
189 | * @param string $program The program to check for.
190 | * @return string
191 | */
192 | public static function guess_path( $program ) {
193 | $os = Revisr_Compatibility::get_os();
194 | $program = Revisr_Admin::escapeshellarg( $program );
195 |
196 | if ( $os['code'] !== 'WIN' ) {
197 | $path = exec( "which $program" );
198 | } else {
199 | $path = exec( "where $program" );
200 | }
201 |
202 | if ( $path ) {
203 | return $path;
204 | } else {
205 | return __( 'Not Found', 'revisr' );
206 | }
207 | }
208 |
209 | /**
210 | * Checks if the exec() function is enabled.
211 | * @access public
212 | * @return string
213 | */
214 | public static function server_has_exec() {
215 | if ( function_exists( 'exec' ) ) {
216 | return 'true';
217 | }
218 | return 'false';
219 | }
220 |
221 | /**
222 | * Checks if Revisr has write permissions to the repository.
223 | * @access public
224 | * @param string $path The path to the repository.
225 | * @return string
226 | */
227 | public static function server_has_permissions( $path ) {
228 | if ( ! is_writable( $path ) || ! is_writeable( $path . DIRECTORY_SEPARATOR . 'config' ) ) {
229 | return 'false';
230 | }
231 | return 'true';
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/classes/class-revisr-cron.php:
--------------------------------------------------------------------------------
1 | 604800,
27 | 'display' => __( 'Weekly', 'revisr' )
28 | );
29 | return $schedules;
30 | }
31 |
32 | /**
33 | * The main "automatic backup" event.
34 | * @access public
35 | */
36 | public function run_automatic_backup() {
37 |
38 | revisr()->git = new Revisr_Git();
39 | revisr()->db = new Revisr_DB();
40 | $backup_type = revisr()->git->get_config( 'revisr', 'automatic-backups' ) ? revisr()->git->get_config( 'revisr', 'automatic-backups' ) : 'none';
41 |
42 | // Make sure backups have been enabled for this environment.
43 | if ( 'none' !== $backup_type ) {
44 |
45 | // Defaults.
46 | $date = date("F j, Y");
47 | $files = revisr()->git->status() ? revisr()->git->status() : array();
48 | $commit_msg = sprintf( __( '%s backup - %s', 'revisr' ), ucfirst( $backup_type ), $date );
49 |
50 | // Stage the files and commit.
51 | revisr()->git->stage_files( $files );
52 | revisr()->git->commit( $commit_msg );
53 |
54 | // Backup the DB.
55 | revisr()->db->backup();
56 |
57 | // Log result - TODO: improve error handling as necessary.
58 | $log_msg = sprintf( __( 'The %s backup was successful.', 'revisr' ), $backup_type );
59 | Revisr_Admin::log( $log_msg, 'backup' );
60 |
61 | }
62 |
63 | }
64 |
65 | /**
66 | * Processes the "auto-pull" functionality.
67 | * @access public
68 | */
69 | public function run_autopull() {
70 |
71 | revisr()->git = new Revisr_Git();
72 |
73 | // If auto-pull isn't enabled, we definitely don't want to do this.
74 | if ( revisr()->git->get_config( 'revisr', 'auto-pull' ) !== 'true' ) {
75 | wp_die( __( 'Cheatin’ uh?', 'revisr' ) );
76 | }
77 |
78 | // Verify the provided token matches the token stored locally.
79 | $remote = new Revisr_Remote();
80 | $remote->check_token();
81 |
82 | // If we're still running at this point, we've successfully authenticated.
83 | revisr()->git->reset();
84 | revisr()->git->fetch();
85 |
86 | // Grab the commits that need to be pulled.
87 | $commits_since = revisr()->git->run( 'log', array( revisr()->git->branch . '..' . revisr()->git->remote . '/' . revisr()->git->branch, '--pretty=oneline' ) );
88 |
89 | // Maybe backup the database.
90 | if ( revisr()->git->get_config( 'revisr', 'import-pulls' ) === 'true' ) {
91 | revisr()->db = new Revisr_DB();
92 | revisr()->db->backup();
93 | $undo_hash = revisr()->git->current_commit();
94 | revisr()->git->set_config( 'revisr', 'last-db-backup', $undo_hash );
95 | }
96 |
97 | // Pull the changes or return an error on failure.
98 | revisr()->git->pull( $commits_since );
99 |
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/classes/class-revisr-db-backup.php:
--------------------------------------------------------------------------------
1 | build_conn( $table );
28 |
29 | // Grab the path to use for mysqldump.
30 | $path = $this->get_path();
31 |
32 | // Backup the table.
33 | $current_dir = getcwd();
34 | chdir( $this->backup_dir );
35 | exec( "{$path}mysqldump $conn > revisr_$table.sql --skip-comments", $output, $return_code );
36 | chdir( $current_dir );
37 |
38 | // Handle any errors
39 | if ( 0 !== $return_code ) {
40 | return false;
41 | }
42 |
43 | // Add the table into version control.
44 | $this->add_table( $table );
45 |
46 | // Makes sure that the backup file exists and is not empty.
47 | return $this->verify_backup( $table );
48 |
49 | }
50 |
51 | /**
52 | * Backs up a single database table using the WordPress database class.
53 | * @access public
54 | * @param string $table The database table to backup.
55 | * @return boolean
56 | */
57 | public function backup_table_wpdb( $table ) {
58 |
59 | $table = esc_sql( $table );
60 |
61 | // Initialize the results, ultimately stored in the backup file.
62 | $results = '';
63 |
64 | // An empty array to store the queries for the table in later.
65 | $queries = array();
66 |
67 | // Grab the SQL needed to create the table.
68 | $show_create = $this->wpdb->get_row( "SHOW CREATE TABLE `$table`" );
69 | $want = 'Create Table';
70 |
71 | if ( $show_create ) {
72 |
73 | // Store the table schema in the backup file.
74 | $results .= "DROP TABLE IF EXISTS `$table`;" . PHP_EOL;
75 | $results .= $show_create->$want . ';' . PHP_EOL;
76 |
77 | // Grab the content of the database table.
78 | foreach ( $this->wpdb->get_results( "SELECT * FROM `$table`" ) as $row ) {
79 |
80 | $vals = array();
81 |
82 | foreach ( get_object_vars( $row ) as $i => $v ) {
83 | $vals[] = sprintf( "'%s'", esc_sql( $v ) );
84 | }
85 |
86 | $queries[] = sprintf( "(%s)", implode( ',', $vals ) );
87 | }
88 |
89 | if ( ! empty( $queries ) ) {
90 | // Implode the queries and generate the rest of the SQL file.
91 | $results .= "LOCK TABLES `$table` WRITE;" . PHP_EOL;
92 | $results .= "INSERT INTO `$table` VALUES " . implode( ', ', $queries ) . ';' . PHP_EOL;
93 | $results .= 'UNLOCK TABLES;' . PHP_EOL;
94 | }
95 |
96 | }
97 |
98 | // Store the contents of the SQL file.
99 | file_put_contents( $this->backup_dir . "revisr_$table.sql", $results );
100 | $this->add_table( $table );
101 |
102 | // Verify the backup was successful and return a boolean.
103 | return $this->verify_backup( $table );
104 | }
105 |
106 | /**
107 | * Processes the results and alerts the user as necessary.
108 | * @access public
109 | * @param array $args An array containing the results of the backup.
110 | * @return boolean
111 | */
112 | public function callback( $args ) {
113 |
114 | if ( in_array( false, $args ) ) {
115 | $msg = __( 'Error backing up the database.', 'revisr' );
116 | Revisr_Admin::alert( $msg, true );
117 | Revisr_Admin::log( $msg, 'error' );
118 | } else {
119 | $msg = __( 'Successfully backed up the database.', 'revisr' );
120 | Revisr_Admin::alert( $msg );
121 | Revisr_Admin::log( $msg, 'backup' );
122 |
123 | // Fires after a successful database backup.
124 | do_action( 'revisr_post_db_backup' );
125 |
126 | return true;
127 | }
128 |
129 | return false;
130 | }
131 |
132 | }
133 |
134 |
--------------------------------------------------------------------------------
/classes/class-revisr-db-import.php:
--------------------------------------------------------------------------------
1 | build_conn();
28 |
29 | // Grab the path to use for MySQL.
30 | $path = $this->get_path();
31 |
32 | // Grab the site url.
33 | $live_url = site_url();
34 |
35 | // Import the table.
36 | $current_dir = getcwd();
37 | chdir( $this->backup_dir );
38 | exec( "{$path}mysql {$conn} < revisr_$table.sql", $output, $return_code );
39 | chdir( $current_dir );
40 |
41 | // Handle any errors.
42 | if ( 0 !== $return_code ) {
43 | Revisr_Admin::log( implode( ' ', $output ), 'error' );
44 | return false;
45 | }
46 |
47 | // Run a search replace if necessary.
48 | if ( $replace_url !== '' && $replace_url !== false ) {
49 | $this->revisr_srdb( $table, $replace_url, $live_url );
50 | }
51 |
52 | // If we're still running at this point, everything worked.
53 | return true;
54 | }
55 |
56 | /**
57 | * Imports a single database table using the WordPress database class.
58 | * @access public
59 | * @param string $table The table to import
60 | * @return array An array of the results.
61 | */
62 | public function import_table_wpdb( $table, $replace_url = '' ) {
63 |
64 | $live_url = site_url();
65 | $fh = fopen( "{$this->backup_dir}revisr_$table.sql", 'r' );
66 | $size = filesize( "{$this->backup_dir}revisr_$table.sql" );
67 | $status = array(
68 | 'errors' => 0,
69 | 'updates' => 0
70 | );
71 |
72 | while( !feof( $fh ) ) {
73 | $query = trim( stream_get_line( $fh, $size, ';' . PHP_EOL ) );
74 | if ( empty( $query ) ) {
75 | $status['dropped_queries'][] = $query;
76 | continue;
77 | }
78 | if ( $this->wpdb->query( $query ) === false ) {
79 | $status['errors']++;
80 | $status['bad_queries'][] = $query;
81 | } else {
82 | $status['updates']++;
83 | $status['good_queries'][] = $query;
84 | }
85 | }
86 |
87 | fclose( $fh );
88 |
89 | if ( '' !== $replace_url ) {
90 | $this->revisr_srdb( $table, $replace_url, $live_url );
91 | }
92 |
93 | if ( 0 !== $status['errors'] ) {
94 | return false;
95 | }
96 | return true;
97 | }
98 |
99 | /**
100 | * Processes the results and alerts the user as necessary.
101 | * @access public
102 | * @param array $args An array containing the results of the backup.
103 | * @return boolean
104 | */
105 | public function callback( $args ) {
106 |
107 | if ( in_array( false, $args ) ) {
108 |
109 | // There were one or more errors with the import.
110 | $msg = __( 'Error importing the database.', 'revisr' );
111 | Revisr_Admin::log( $msg, 'error' );
112 | Revisr_Admin::alert( $msg, true );
113 |
114 | } else {
115 |
116 | // Everything imported properly.
117 | $get_hash = revisr()->git->run( 'config', array( 'revisr.last-db-backup' ) );
118 | $revert_link = '';
119 |
120 | if ( is_array( $get_hash ) ) {
121 | $undo_hash = $get_hash[0];
122 | $undo_url = get_admin_url() . 'admin-post.php?action=process_revert&revert_type=db&db_hash=' . $undo_hash;
123 | $undo_nonced = wp_nonce_url( $undo_url, 'revisr_revert_nonce', 'revisr_revert_nonce' );
124 | $revert_link = '' . __( 'Undo', 'revisr') . ' ';
125 | revisr()->git->run( 'config', array( '--unset', 'revisr.last-db-backup' ) );
126 | }
127 |
128 | // Alert the user.
129 | $msg = sprintf( __( 'Successfully imported the database. %s', 'revisr'), $revert_link );
130 | Revisr_Admin::log( $msg, 'import' );
131 | Revisr_Admin::alert( $msg );
132 |
133 | // Fires after a successful database import.
134 | do_action( 'revisr_post_db_import' );
135 |
136 | return true;
137 | }
138 |
139 | return false;
140 | }
141 |
142 | /**
143 | * Gets the columns in a table.
144 | * @access public
145 | * @param string $table The table to check.
146 | * @return array
147 | */
148 | public function get_columns( $table ) {
149 | $primary_key = null;
150 | $columns = array();
151 | $fields = $this->wpdb->get_results( 'DESCRIBE ' . $table );
152 |
153 | if ( is_array( $fields ) ) {
154 | foreach ( $fields as $column ) {
155 | $columns[] = $column->Field;
156 | if ( $column->Key == 'PRI' ) {
157 | $primary_key = $column->Field;
158 | }
159 | }
160 | }
161 |
162 | return array( $primary_key, $columns );
163 | }
164 |
165 | /**
166 | * Adapated from interconnect/it's search/replace script.
167 | * Modified to use WordPress wpdb functions instead of PHP's native mysql/pdo functions.
168 | *
169 | * @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
170 | *
171 | * @access private
172 | * @param string $table The table to run the replacement on.
173 | * @param string $search The string to replace.
174 | * @param string $replace The string to replace with.
175 | * @return boolean
176 | */
177 | private function revisr_srdb( $table, $search = '', $replace = '' ) {
178 |
179 | $table = esc_sql( $table );
180 |
181 | // Get a list of columns in this table.
182 | list( $primary_key, $columns ) = $this->get_columns( $table );
183 |
184 | // Bail out early if there isn't a primary key.
185 | if ( null === $primary_key ) {
186 | return false;
187 | }
188 |
189 | // Count the number of rows we have in the table if large we'll split into blocks, This is a mod from Simon Wheatley
190 | $row_count = $this->wpdb->get_var( "SELECT COUNT(*) FROM $table" );
191 | if ( $row_count == 0 ) {
192 | return true;
193 | }
194 |
195 | $page_size = 50000;
196 | $pages = ceil( $row_count / $page_size );
197 |
198 | for( $page = 0; $page < $pages; $page++ ) {
199 |
200 | $current_row = 0;
201 | $start = $page * $page_size;
202 | $end = $page_size;
203 |
204 | // Grab the content of the table.
205 | $data = $this->wpdb->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A );
206 |
207 | // Loop through the data.
208 | foreach ( $data as $row ) {
209 | $current_row++;
210 | $update_sql = array();
211 | $where_sql = array();
212 | $upd = false;
213 |
214 | foreach( $columns as $column ) {
215 |
216 | $data_to_fix = $row[ $column ];
217 |
218 | if ( $column == $primary_key ) {
219 | $where_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $data_to_fix ) . '"';
220 | continue;
221 | }
222 |
223 | // Run a search replace on the data that'll respect the serialisation.
224 | $edited_data = $this->recursive_unserialize_replace( $search, $replace, $data_to_fix );
225 |
226 | // Something was changed
227 | if ( $edited_data != $data_to_fix ) {
228 | $update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $edited_data ) . '"';
229 | $upd = true;
230 | }
231 |
232 | }
233 |
234 | if ( $upd && ! empty( $where_sql ) ) {
235 | $sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
236 | $result = $this->wpdb->query( $sql );
237 | if ( ! $result ) {
238 | $error_msg = sprintf( __( 'Error updating the table: %s.', 'revisr' ), $table );
239 | }
240 | }
241 |
242 | }
243 |
244 | }
245 |
246 | $this->wpdb->flush();
247 | if ( isset( $error_msg ) ) {
248 | Revisr_Admin::log( $error_msg, 'error' );
249 | return false;
250 | }
251 |
252 | }
253 |
254 | /**
255 | * Adapated from interconnect/it's search/replace script.
256 | *
257 | * @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
258 | *
259 | * Take a serialised array and unserialise it replacing elements as needed and
260 | * unserialising any subordinate arrays and performing the replace on those too.
261 | *
262 | * @access private
263 | * @param string $from String we're looking to replace.
264 | * @param string $to What we want it to be replaced with.
265 | * @param array $data Used to pass any subordinate arrays back to in.
266 | * @param bool $serialised Does the array passed via $data need serialising.
267 | *
268 | * @return string|array The original array with all elements replaced as needed.
269 | */
270 | private function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = false ) {
271 | try {
272 |
273 | if ( is_string( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) {
274 | $data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true );
275 | }
276 |
277 | elseif ( is_array( $data ) ) {
278 | $_tmp = array( );
279 | foreach ( $data as $key => $value ) {
280 | $_tmp[ $key ] = $this->recursive_unserialize_replace( $from, $to, $value, false );
281 | }
282 |
283 | $data = $_tmp;
284 | unset( $_tmp );
285 | }
286 |
287 | // Submitted by Tina Matter
288 | elseif ( is_object( $data ) ) {
289 | // $data_class = get_class( $data );
290 | $_tmp = $data; // new $data_class( );
291 | $props = get_object_vars( $data );
292 | foreach ( $props as $key => $value ) {
293 | $_tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false );
294 | }
295 |
296 | $data = $_tmp;
297 | unset( $_tmp );
298 | }
299 |
300 | else {
301 | if ( is_string( $data ) )
302 | $data = str_replace( $from, $to, $data );
303 | }
304 |
305 | if ( $serialised )
306 | return serialize( $data );
307 |
308 | } catch( Exception $error ) {
309 | Revisr_Admin::log( $error, 'error' );
310 | }
311 |
312 | return $data;
313 | }
314 |
315 | }
316 |
--------------------------------------------------------------------------------
/classes/class-revisr-i18n.php:
--------------------------------------------------------------------------------
1 | domain,
35 | false,
36 | dirname( dirname( plugin_basename( __FILE__ ) ) ) . 'languages/'
37 | );
38 | }
39 |
40 | /**
41 | * Set the domain equal to that of the specified domain.
42 | * @access public
43 | * @param string $domain The domain that represents the locale of this plugin.
44 | */
45 | public function set_domain( $domain ) {
46 | $this->domain = $domain;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/classes/class-revisr-meta-boxes.php:
--------------------------------------------------------------------------------
1 | 2, 'default' => 2 ) );
32 | }
33 |
34 | /**
35 | * Initializes JS for the Revisr custom meta boxes.
36 | * @access public
37 | */
38 | public function init_meta_boxes() {
39 | ?>
40 |
41 | git->status();
63 | $total_pending = count( $output );
64 | $text = sprintf( __( 'There are %s untracked files that can be added to this commit.', 'revisr' ), $total_pending, revisr()->git->branch );
65 | echo " " . $text . " ";
66 | _e( 'Use the boxes below to select the files to include in this commit. Only files in the "Staged Files" section will be included. Double-click files marked as "Modified" to view the changes to the file. ', 'revisr' );
67 | if ( is_array( $output ) ) {
68 | ?>
69 |
70 |
71 |
72 |
73 | {$file} [{$status}]";
81 | }
82 | ?>
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | ';
121 |
122 | // Files were included in this commit.
123 | if ( 0 !== count( $commit['committed_files'] ) ) {
124 |
125 | printf( __('
%s files were included in this commit. Double-click files marked as "Modified" to view the changes in a diff.', 'revisr' ), $commit['files_changed'] );
126 |
127 | echo '
';
128 | echo '
';
129 |
130 | // Display the files that were included in the commit.
131 | foreach ( $commit['committed_files'] as $result ) {
132 |
133 | $result = str_replace( '"', '', $result );
134 | $short_status = substr( $result, 0, 3 );
135 | $file = substr( $result, 2 );
136 | $status = Revisr_Git::get_status( $short_status );
137 |
138 | printf( '%s [%s] ', $result, $file, $status );
139 | }
140 |
141 | echo ' ';
142 |
143 | } else {
144 | printf( '
%s
', __( 'No files were included in this commit.', 'revisr' ) );
145 | }
146 |
147 | echo '
';
148 |
149 | }
150 |
151 | /**
152 | * Displays the "Add Tag" meta box on the sidebar.
153 | * @access public
154 | */
155 | public function add_tag_meta() {
156 | printf(
157 | '%s
158 | ',
159 | __( 'Tag Name:', 'revisr' )
160 | );
161 | }
162 |
163 | /**
164 | * Displays the "Save Commit" meta box in the sidebar.
165 | * @access public
166 | */
167 | public function save_commit_meta() {
168 | ?>
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 | git->branch; ?>
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 | git->get_config( 'revisr', 'auto-push' ) == 'true' ): ?>
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 | %s', 'revisr' ), date_i18n( $time_format, $commit['time'] ) );
228 |
229 | if ( false === $commit['status'] ) {
230 | $commit['status'] = __( 'Error', 'revisr' );
231 | $revert_btn = '' . __( 'Revert to this Commit', 'revisr' ) . ' ';
232 | } else {
233 | $revert_btn = '' . __( 'Revert to this Commit', 'revisr' ) . ' ';
234 | }
235 |
236 | ?>
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
281 |
";
282 | }
283 |
284 | }
285 |
--------------------------------------------------------------------------------
/classes/class-revisr-remote.php:
--------------------------------------------------------------------------------
1 | git->get_config( 'revisr', 'token' );
25 |
26 | if ( $check === false ) {
27 |
28 | // If there is no token, generate a new one and save it.
29 | $token = wp_generate_password( 16, false, false );
30 | revisr()->git->set_config( 'revisr', 'token', $token );
31 |
32 | // Make sure that the token saved correctly.
33 | $new_token = revisr()->git->get_config( 'revisr', 'token' );
34 | if ( is_string( $new_token ) && hash_equals( $new_token, $token ) ) {
35 | if ( $new_token !== false ) {
36 | return $new_token;
37 | }
38 | } else {
39 | return false;
40 | }
41 |
42 | } else {
43 | // Return the already saved token.
44 | return $check;
45 | }
46 | }
47 |
48 | /**
49 | * Verifies a token is valid.
50 | * @access public
51 | * @return boolean
52 | */
53 | public function check_token( $token = '' ) {
54 |
55 | // Allow testing of this function.
56 | if ( $token !== '' ) {
57 | $token_to_check = $token;
58 | }
59 |
60 | // This is set in the Webhook URL.
61 | if ( isset( $_REQUEST['token'] ) && $_REQUEST['token'] !== '' ) {
62 | $token_to_check = $_REQUEST['token'];
63 | }
64 |
65 | // Compare the tokens and return true if a complete match.
66 | if ( isset( $token_to_check ) ) {
67 | $safe_token = revisr()->git->get_config( 'revisr', 'token' );
68 | if ( hash_equals( $safe_token, $token_to_check ) ) {
69 | return true;
70 | }
71 | }
72 |
73 | // Die if not.
74 | wp_die( __( 'Cheatin’ uh?', 'revisr' ) );
75 | }
76 |
77 | /**
78 | * Sends a new HTTP request to the live site.
79 | * @access public
80 | */
81 | public function send_request() {
82 | $body = array(
83 | 'action' => 'revisr_update'
84 | );
85 | $args = array(
86 | 'method' => 'POST',
87 | 'timeout' => '30',
88 | 'redirection' => '5',
89 | 'httpversion' => '1.0',
90 | 'blocking' => true,
91 | 'headers' => array(),
92 | 'body' => $body
93 | );
94 |
95 | // Get the URL and send the request.
96 | $get_url = revisr()->git->get_config( 'revisr', 'webhook-url' );
97 |
98 | if ( $get_url !== false ) {
99 | $webhook = urldecode( $get_url );
100 | $request = wp_remote_post( $webhook, $args );
101 | if ( is_wp_error( $request ) ) {
102 | Revisr_Admin::log( __( 'Error contacting webhook URL.', 'revisr' ), 'error' );
103 | } else {
104 | Revisr_Admin::log( __( 'Sent update request to the webhook.', 'revisr' ), 'push' );
105 | }
106 | }
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/classes/class-revisr-settings.php:
--------------------------------------------------------------------------------
1 | settings_fields = new Revisr_Settings_Fields();
30 | }
31 |
32 | /**
33 | * Initialize the settings.
34 | * @access public
35 | */
36 | public function init_settings() {
37 | $this->revisr_add_settings_sections();
38 | $this->revisr_add_settings_fields();
39 | $this->revisr_register_settings();
40 | }
41 |
42 | /**
43 | * Registers the settings sections.
44 | * @access public
45 | */
46 | public function revisr_add_settings_sections() {
47 | add_settings_section(
48 | 'revisr_general_settings',
49 | 'General Settings',
50 | array( $this->settings_fields, 'revisr_general_settings_callback' ),
51 | 'revisr_general_settings'
52 | );
53 | add_settings_section(
54 | 'revisr_remote_settings',
55 | 'Repository Settings',
56 | array( $this->settings_fields, 'revisr_remote_settings_callback' ),
57 | 'revisr_remote_settings'
58 | );
59 | add_settings_section(
60 | 'revisr_database_settings',
61 | 'Database Settings',
62 | array( $this->settings_fields, 'revisr_database_settings_callback' ),
63 | 'revisr_database_settings'
64 | );
65 | }
66 |
67 | /**
68 | * Registers the settings fields.
69 | * @access public
70 | */
71 | public function revisr_add_settings_fields() {
72 | add_settings_field(
73 | 'username',
74 | __( 'Git Username', 'revisr' ),
75 | array( $this->settings_fields, 'username_callback' ),
76 | 'revisr_general_settings',
77 | 'revisr_general_settings'
78 | );
79 | add_settings_field(
80 | 'email',
81 | __( 'Git Email', 'revisr'),
82 | array( $this->settings_fields, 'email_callback' ),
83 | 'revisr_general_settings',
84 | 'revisr_general_settings'
85 | );
86 | add_settings_field(
87 | 'git_path',
88 | __( 'Git Path', 'revisr' ),
89 | array( $this->settings_fields, 'git_path_callback' ),
90 | 'revisr_general_settings',
91 | 'revisr_general_settings'
92 | );
93 | add_settings_field(
94 | 'gitignore',
95 | __( 'Files/Directories to ignore', 'revisr'),
96 | array( $this->settings_fields, 'gitignore_callback' ),
97 | 'revisr_general_settings',
98 | 'revisr_general_settings'
99 | );
100 | add_settings_field(
101 | 'automatic_backups',
102 | __( 'Automatic backup schedule', 'revisr' ),
103 | array( $this->settings_fields, 'automatic_backups_callback' ),
104 | 'revisr_general_settings',
105 | 'revisr_general_settings'
106 | );
107 | add_settings_field(
108 | 'notifications',
109 | __( 'Enable email notifications?', 'revisr' ),
110 | array( $this->settings_fields, 'notifications_callback' ),
111 | 'revisr_general_settings',
112 | 'revisr_general_settings'
113 | );
114 | add_settings_field(
115 | 'uninstall_on_delete',
116 | __( 'Remove data on uninstall?', 'revisr' ),
117 | array( $this->settings_fields, 'uninstall_on_delete_callback' ),
118 | 'revisr_general_settings',
119 | 'revisr_general_settings'
120 | );
121 | add_settings_field(
122 | 'remote_name',
123 | __( 'Remote Name', 'revisr'),
124 | array( $this->settings_fields, 'remote_name_callback' ),
125 | 'revisr_remote_settings',
126 | 'revisr_remote_settings'
127 | );
128 | add_settings_field(
129 | 'remote_url',
130 | __( 'Remote URL', 'revisr'),
131 | array( $this->settings_fields, 'remote_url_callback' ),
132 | 'revisr_remote_settings',
133 | 'revisr_remote_settings'
134 | );
135 | add_settings_field(
136 | 'webhook_url',
137 | __( 'Revisr Webhook URL', 'revisr' ),
138 | array( $this->settings_fields, 'webhook_url_callback' ),
139 | 'revisr_remote_settings',
140 | 'revisr_remote_settings'
141 | );
142 | add_settings_field(
143 | 'auto_push',
144 | __( 'Automatically push new commits?', 'revisr' ),
145 | array( $this->settings_fields, 'auto_push_callback' ),
146 | 'revisr_remote_settings',
147 | 'revisr_remote_settings'
148 | );
149 | add_settings_field(
150 | 'auto_pull',
151 | __( 'Automatically pull new commits?', 'revisr' ),
152 | array( $this->settings_fields, 'auto_pull_callback' ),
153 | 'revisr_remote_settings',
154 | 'revisr_remote_settings'
155 | );
156 | add_settings_field(
157 | 'tracked_tables',
158 | __( 'Database tables to track', 'revisr' ),
159 | array( $this->settings_fields, 'tracked_tables_callback' ),
160 | 'revisr_database_settings',
161 | 'revisr_database_settings'
162 | );
163 | add_settings_field(
164 | 'reset_db',
165 | __( 'Import Options', 'revisr' ),
166 | array( $this->settings_fields, 'reset_db_callback' ),
167 | 'revisr_database_settings',
168 | 'revisr_database_settings'
169 | );
170 | add_settings_field(
171 | 'development_url',
172 | __( 'Development URL', 'revisr'),
173 | array( $this->settings_fields, 'development_url_callback' ),
174 | 'revisr_database_settings',
175 | 'revisr_database_settings'
176 | );
177 | add_settings_field(
178 | 'db_driver',
179 | __( 'Database Driver', 'revisr' ),
180 | array( $this->settings_fields, 'db_driver_callback' ),
181 | 'revisr_database_settings',
182 | 'revisr_database_settings'
183 | );
184 | add_settings_field(
185 | 'mysql_path',
186 | __( 'Path to MySQL', 'revisr' ),
187 | array( $this->settings_fields, 'mysql_path_callback' ),
188 | 'revisr_database_settings',
189 | 'revisr_database_settings'
190 | );
191 | }
192 |
193 | /**
194 | * Register the settings fields with WordPress.
195 | * @access public
196 | */
197 | public function revisr_register_settings() {
198 | register_setting(
199 | 'revisr_general_settings',
200 | 'revisr_general_settings'
201 | );
202 | register_setting(
203 | 'revisr_remote_settings',
204 | 'revisr_remote_settings',
205 | array( $this, 'sanitize_remote' )
206 | );
207 | register_setting(
208 | 'revisr_database_settings',
209 | 'revisr_database_settings'
210 | );
211 | }
212 |
213 | /**
214 | * Sanitizes the "Remote Settings" fields so that URL's can be stored.
215 | * @access public
216 | * @param array $input The data from the form.
217 | * @return array
218 | */
219 | public function sanitize_remote( $input ) {
220 | if ( isset( $input['webhook_url'] ) ) {
221 | $input['webhook_url'] = urlencode( $input['webhook_url'] );
222 | }
223 | return $input;
224 | }
225 |
226 | }
227 |
--------------------------------------------------------------------------------
/classes/index.php:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | ./tests/
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/templates/index.php:
--------------------------------------------------------------------------------
1 | branch_table->prepare_items();
18 |
19 | ?>
20 |
21 |
22 |
23 |
24 |
25 |
' . $msg . '
';
31 | break;
32 | case "create_error":
33 | $msg = __( 'Failed to create the new branch.', 'revisr' );
34 | if ( revisr()->git->is_branch( $_GET['branch'] ) ) {
35 | $msg = sprintf( esc_html__( 'Failed to create branch: %s (branch already exists).', 'revisr' ), $_GET['branch'] );
36 | }
37 | echo '';
38 | break;
39 | case "delete_success":
40 | $msg = sprintf( esc_html__( 'Successfully deleted branch: %s.', 'revisr' ), $_GET['branch'] );
41 | echo '';
42 | break;
43 | case "delete_fail":
44 | $msg = sprintf( esc_html__( 'Failed to delete branch: %s.', 'revisr' ), $_GET['branch'] );
45 | echo '';
46 | default:
47 | // Do nothing.
48 | }
49 | }
50 | ?>
51 |
52 |
53 |
54 |
55 |
58 |
59 |
60 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/templates/pages/commits.php:
--------------------------------------------------------------------------------
1 | commits_table->prepare_items();
18 |
19 | // Gets current branches for filtering.
20 | $branches = revisr()->git->get_branches();
21 |
22 | ?>
23 |
24 |
25 |
26 |
27 |
28 | commits_table->render_views(); ?>
29 |
30 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/templates/pages/dashboard.php:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 | activity_table->prepare_items();
32 | ?>
33 |
34 |
35 |
36 |
37 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
53 |
54 |
55 |
56 |
57 |
58 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/templates/pages/help.php:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 | plugin support forums.', 'revisr' ); ?>
19 |
20 | GitHub!', 'revisr' ); ?>
21 |
22 |
41 |
--------------------------------------------------------------------------------
/templates/pages/index.php:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/templates/pages/settings.php:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
21 |
22 |
Settings updated successfully.
', 'revisr' );
26 | }
27 | if ( isset( $_GET['init'] ) && $_GET['init'] == 'success' ) {
28 | printf( '
',
29 | __( 'Successfully initialized a new repository. Please confirm the settings below before creating your first commit.', 'revisr' )
30 | );
31 | }
32 | ?>
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/templates/pages/view-commit.php:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 |
26 | %s.', 'revisr' ), revisr()->git->branch );
29 | echo '
';
30 | }
31 | ?>
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/templates/partials/checkout-remote-form.php:
--------------------------------------------------------------------------------
1 | git->current_remote() ) + 1 );
20 |
21 | if ( revisr()->git->is_branch( $local ) ) {
22 | $text = sprintf( __( 'Revisr detected that local branch %s may already be tracking remote branch %s . Do you want to checkout local branch %s ?', 'revisr' ), $local, $remote, $local );
23 | } else {
24 | $text = sprintf( __( 'This will checkout remote branch %s into a new local branch %s .', 'revisr' ), $remote, $local );
25 | }
26 |
27 | ?>
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
git->get_config( 'revisr', 'import-checkouts' ), 'true' ); ?> />
36 |
37 |
38 |
39 |
40 |
41 |
42 | git->is_branch( $local ) ): ?>
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/templates/partials/delete-branch-form.php:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
This will delete all local work on branch %s .', 'revisr' ), $branch ); ?>
29 |
30 |
31 |
32 |
%s?', 'revisr' ), $branch ); ?>
33 |
34 | git->current_remote() ) + 1 ); ?>
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/templates/partials/discard-form.php:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/templates/partials/import-tables-form.php:
--------------------------------------------------------------------------------
1 | db->get_tables_not_in_db();
18 |
19 | ?>
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
$table ";
30 | }
31 | ?>
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/templates/partials/index.php:
--------------------------------------------------------------------------------
1 | %s into the current branch. In the event of conflicts, Revisr will keep the version from the branch being merged in.', 'revisr' ), esc_html( $_GET['branch'] ) );
18 |
19 | ?>
20 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/templates/partials/pull-form.php:
--------------------------------------------------------------------------------
1 | git->run( 'log', array( revisr()->git->branch . '..' . revisr()->git->remote . '/' . revisr()->git->branch, '--format=%h - %s' ) );
20 |
21 | // If none are detected, do an extra fetch, just to be sure.
22 | if ( is_array( $unpulled ) && 0 === count( $unpulled ) ) {
23 | revisr()->git->fetch();
24 | $unpulled = revisr()->git->run( 'log', array( revisr()->git->branch . '..' . revisr()->git->remote . '/' . revisr()->git->branch, '--format=%h - %s' ) );
25 | }
26 |
27 | ?>
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/templates/partials/push-form.php:
--------------------------------------------------------------------------------
1 | git->run( 'log', array( revisr()->git->branch, '--not', '--remotes', '--oneline' ) );
20 |
21 | ?>
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | git->has_remote() ): ?>
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | ' . $hash . '';
45 | $title = substr( $commit, 7 );
46 |
47 | $commit_li = $link . $title;
48 | ?>
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/templates/partials/revert-form.php:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | revisr = revisr();
15 | $this->revisr->git = new Revisr_Git();
16 | $this->revisr->db = new Revisr_DB();
17 | $this->revisr->admin = new Revisr_Admin();
18 | }
19 |
20 | /**
21 | * Tests the alert() method.
22 | */
23 | function test_alert() {
24 | // Tests for a standard alert.
25 | Revisr_Admin::alert( __( 'test_alert' ) );
26 | $alert_transient = get_transient( 'revisr_alert' );
27 | $this->assertEquals( 'test_alert', $alert_transient );
28 | // Tests for an error.
29 | $this->revisr->admin->alert( 'test_error', true );
30 | $error_transient = get_transient( 'revisr_error' );
31 | $this->assertEquals( 'test_error', $error_transient );
32 | }
33 |
34 | /**
35 | * Tests the Revisr_Admin::clear_transients() method.
36 | */
37 | function test_clear_transients() {
38 | //First set a transient and make sure it exists.
39 | Revisr_Admin::alert( 'test_error', true );
40 | $transient = get_transient( 'revisr_error' );
41 | $this->assertEquals( 'test_error', $transient );
42 |
43 | // Clear the transients and make sure they're really gone.
44 | Revisr_Admin::clear_transients();
45 | $new_transient = get_transient( 'revisr_error' );
46 | $this->assertEquals( false, $new_transient );
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/tests/test-compatibility.php:
--------------------------------------------------------------------------------
1 | assertArrayHasKey( 'code', $os );
11 | $this->assertArrayHasKey( 'name', $os );
12 | }
13 |
14 | /**
15 | * Tests the guess_path() method.
16 | */
17 | function test_get_path() {
18 | $path = Revisr_Compatibility::guess_path( 'mysql' );
19 | $this->assertContains( 'mysql', $path );
20 | }
21 |
22 | /**
23 | * Tests the server_has_exec() method.
24 | */
25 | function test_server_has_exec() {
26 | $this->assertEquals( 'true', Revisr_Compatibility::server_has_exec() );
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/tests/test-db-backup.php:
--------------------------------------------------------------------------------
1 | revisr = revisr();
23 | $this->revisr->git = new Revisr_Git;
24 | $this->revisr->db = new Revisr_DB;
25 | $this->backup = new Revisr_DB_Backup;
26 | }
27 |
28 | /**
29 | * Tests the Revisr_DB_Backup->backup_table_mysql() method.
30 | * @access public
31 | */
32 | public function test_backup_table_mysql() {
33 | $backup = $this->backup->backup_table_mysql( 'wptests_posts' );
34 | $verify = $this->revisr->db->verify_backup( 'wptests_posts' );
35 |
36 | $this->assertEquals( true, $backup );
37 | $this->assertEquals( true, $verify );
38 |
39 | }
40 |
41 | /**
42 | * Tests the Revisr_DB_Backup->backup_table_wpdb() method.
43 | * @access public
44 | */
45 | public function test_backup_table_wpdb() {
46 | $backup = $this->backup->backup_table_wpdb( 'wptests_posts' );
47 | $verify = $this->revisr->db->verify_backup( 'wptests_posts' );
48 |
49 | $this->assertEquals( true, $backup );
50 | $this->assertEquals( true, $verify );
51 | }
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/tests/test-db-import.php:
--------------------------------------------------------------------------------
1 | revisr = revisr();
23 | $this->revisr->git = new Revisr_Git;
24 | $this->revisr->db = new Revisr_DB;
25 | $this->import = new Revisr_DB_Import;
26 | }
27 |
28 | /**
29 | * Tests the Revisr_DB_Import->import_table_mysql method.
30 | * @access public
31 | */
32 | public function test_import_table_mysql() {
33 | $import = $this->import->import_table_mysql( 'wptests_posts' );
34 | $this->assertEquals( true, $import );
35 | }
36 |
37 | /**
38 | * Tests the Revisr_DB_Import->import_table_wpdb method.
39 | * @access public
40 | */
41 | public function test_import_table_wpdb() {
42 | $import = $this->import->import_table_wpdb( 'wptests_posts' );
43 | $this->assertEquals( true, $import );
44 | }
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/tests/test-db.php:
--------------------------------------------------------------------------------
1 | revisr = revisr();
15 | $this->revisr->git = new Revisr_Git();
16 | $this->revisr->db = new Revisr_DB();
17 | }
18 |
19 | /**
20 | * Tests the check_port_or_socket() function.
21 | */
22 | function test_check_port_or_socket() {
23 | // Checks for ports or sockets.
24 | $no_port = $this->revisr->db->check_port_or_socket( 'localhost' );
25 | $port = $this->revisr->db->check_port_or_socket( 'localhost:3306' );
26 | $socket = $this->revisr->db->check_port_or_socket( 'localhost:/var/run/mysqld/mysqld.sock' );
27 | $full_url = $this->revisr->db->check_port_or_socket( 'http://localhost:3306' );
28 |
29 | // Runs the assertions.
30 | $this->assertEquals( false, $no_port );
31 |
32 | $this->assertArrayHasKey( 'port', $port );
33 | $this->assertArrayHasKey( 'socket', $port );
34 | $this->assertEquals( 3306, $port['port'] );
35 | $this->assertEquals( null, $port['socket'] );
36 |
37 | $this->assertArrayHasKey( 'port', $socket );
38 | $this->assertArrayHasKey( 'socket', $socket );
39 | $this->assertEquals( null, $socket['port'] );
40 | $this->assertEquals( '/var/run/mysqld/mysqld.sock', $socket['socket'] );
41 |
42 | $this->assertArrayHasKey( 'port', $full_url );
43 | $this->assertArrayHasKey( 'socket', $full_url );
44 | $this->assertEquals( 3306, $full_url['port'] );
45 | $this->assertEquals( null, $full_url['socket'] );
46 | }
47 |
48 | /**
49 | * Tests the setup_env() method.
50 | */
51 | function test_setup_env() {
52 | $this->assertFileExists( ABSPATH . 'wp-content/uploads/revisr-backups/.htaccess' );
53 | $this->assertFileExists( ABSPATH . 'wp-content/uploads/revisr-backups/index.php' );
54 | }
55 |
56 | /**
57 | * Tests the get_tables() method.
58 | */
59 | function test_get_tables() {
60 | $tables = serialize( $this->revisr->db->get_tables() );
61 | $this->assertContains( '_posts', $tables );
62 | $this->assertContains( '_revisr', $tables );
63 |
64 | }
65 |
66 | /**
67 | * Tests the get_sizes() method.
68 | */
69 | function test_get_sizes() {
70 | global $wpdb;
71 | $sizes = $this->revisr->db->get_sizes();
72 | $key = $wpdb->prefix . 'posts';
73 | $this->assertArrayHasKey($key, $sizes );
74 | $this->assertContains( 'MB)', $sizes[$key] );
75 | }
76 |
77 | /**
78 | * Tests the get_tables_not_in_db() method.
79 | */
80 | function test_get_tables_not_in_db() {
81 | file_put_contents( ABSPATH . 'wp-content/uploads/revisr-backups/revisr_faketable.sql', 'test' );
82 | $tables = serialize( $this->revisr->db->get_tables_not_in_db() );
83 | $this->assertContains( 'faketable', $tables );
84 | }
85 |
86 | /**
87 | * Tests a database backup.
88 | */
89 | function test_backup() {
90 | $this->revisr->git->set_config( 'revisr', 'db-tracking', 'all_tables' );
91 | $this->revisr->db->backup();
92 | $this->assertFileExists( ABSPATH . 'wp-content/uploads/revisr-backups/revisr_wptests_posts.sql' );
93 | }
94 |
95 | /**
96 | * Tests the verify_backup() function.
97 | */
98 | function test_verify_backup() {
99 | $verify = $this->revisr->db->verify_backup( 'wptests_posts' );
100 | $this->assertEquals( true, $verify );
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/tests/test-git.php:
--------------------------------------------------------------------------------
1 | revisr = revisr();
15 | $this->revisr->git = new Revisr_Git();
16 | }
17 |
18 | /**
19 | * Restore the Git object.
20 | */
21 | function tearDown() {
22 | if ( $this->revisr->git->current_branch() != 'master' ) {
23 | $this->revisr->git->checkout( 'master' );
24 | }
25 | }
26 |
27 | /**
28 | * Tests the init function.
29 | */
30 | function test_init_repo() {
31 |
32 | define( 'REVISR_SETUP_INIT', true );
33 |
34 | if ( ! $this->revisr->git->is_repo ) {
35 | $this->revisr->git->init_repo();
36 | }
37 | $this->assertEquals( true, $this->revisr->git->is_repo );
38 | }
39 |
40 | /**
41 | * Tests setting the Git username.
42 | */
43 | function test_config() {
44 | // Set the Git username and email address.
45 | $this->revisr->git->set_config( 'user', 'name', 'revisr' );
46 | $this->revisr->git->set_config( 'user', 'email', 'support@expandedfronts.com' );
47 |
48 | // Grab the values via get_config().
49 | $current_user = $this->revisr->git->get_config( 'user', 'name' );
50 | $current_email = $this->revisr->git->get_config( 'user', 'email' );
51 |
52 | $this->assertEquals( 'revisr', $current_user );
53 | $this->assertEquals( 'support@expandedfronts.com', $current_email );
54 | }
55 |
56 |
57 | /**
58 | * Tests for the current Git version.
59 | * Expects string containing "git".
60 | */
61 | function test_version() {
62 | $version = $this->revisr->git->version();
63 | $this->assertStringStartsWith( 'git', $version );
64 | }
65 |
66 | /**
67 | * Tests the current dir with an initialized repository.
68 | */
69 | function test_git_dir() {
70 | $dir = $this->revisr->git->get_git_dir();
71 | $this->assertFileExists( $dir );
72 | $this->assertFileExists( $dir . '/config' );
73 | }
74 |
75 | /**
76 | * Tests that we have the path to Git.
77 | */
78 | function test_git_path() {
79 | $path = $this->revisr->git->get_git_path();
80 | $this->assertContains('git', $path );
81 | }
82 |
83 | /**
84 | * Tests a commit.
85 | */
86 | function test_commit() {
87 | $this->revisr->git->run( 'add', array( '-A' ) );
88 | $this->revisr->git->commit( 'Committed pending files' );
89 | $this->assertEquals( 0, $this->revisr->git->count_untracked() );
90 | }
91 |
92 | /**
93 | * Tests the branches function.
94 | */
95 | function test_branches() {
96 | $branches = $this->revisr->git->get_branches();
97 | $this->assertContains( '* ', $branches[0] );
98 | }
99 |
100 | /**
101 | * Tests creating a new branch.
102 | */
103 | function test_create_branch() {
104 | $this->revisr->git->create_branch( 'testbranch' );
105 | $this->revisr->git->create_branch( 'deletethisbranch' );
106 | $this->assertEquals( true, $this->revisr->git->is_branch( 'testbranch' ) );
107 | $this->assertEquals( true, $this->revisr->git->is_branch( 'deletethisbranch' ) );
108 | }
109 |
110 | /**
111 | * Tests the is_branch function.
112 | */
113 | function test_is_branch() {
114 | $real_branch = $this->revisr->git->is_branch( 'testbranch' );
115 | $fake_branch = $this->revisr->git->is_branch( 'fakebranch' );
116 | $this->assertEquals( true, $real_branch );
117 | $this->assertEquals( false, $fake_branch );
118 | }
119 |
120 | /**
121 | * Tests checking out a branch.
122 | */
123 | function test_checkout() {
124 | $this->revisr->git->checkout( 'testbranch' );
125 | $current_branch = $this->revisr->git->current_branch();
126 | $this->assertEquals( 'testbranch', $current_branch );
127 | }
128 |
129 | /**
130 | * Tests deleting a branch.
131 | */
132 | function test_delete_branch() {
133 | $this->revisr->git->delete_branch( 'testbranch', false );
134 | $this->revisr->git->delete_branch( 'deletethisbranch', false );
135 | $is_branch = $this->revisr->git->is_branch( 'deletethisbranch' );
136 | $this->assertEquals( false, $is_branch );
137 | }
138 |
139 | /**
140 | * Tests the count_untracked() function.
141 | */
142 | function test_count_untracked() {
143 | $dir = $this->revisr->git->get_work_tree();
144 | $time = time();
145 | fopen( $dir . "/sample-file_$time.txt", "w" );
146 | $new_untracked = $this->revisr->git->count_untracked();
147 | $this->assertEquals( 1, $new_untracked );
148 | }
149 |
150 | /**
151 | * Tests the reset functionality.
152 | */
153 | function test_reset() {
154 | $this->revisr->git->reset( '--hard', 'HEAD', true );
155 | $after_reset = $this->revisr->git->count_untracked();
156 | $this->assertEquals( 0, $after_reset );
157 | }
158 |
159 | /**
160 | * Tests the Git status functionality.
161 | */
162 | function test_status() {
163 | $status = $this->revisr->git->status();
164 | $this->assertNotEquals( false, $status );
165 | }
166 |
167 | /**
168 | * Tests the current_commit() function. Expects 7 digit short SHA1 hash.
169 | */
170 | function test_current_commit() {
171 | $current = $this->revisr->git->current_commit();
172 | $length = strlen($current);
173 | $this->assertEquals( 7, $length );
174 | }
175 |
176 | /**
177 | * Test the current_remote() method. Expects origin since we haven't changed it.
178 | */
179 | function test_current_remote() {
180 | $remote = $this->revisr->git->current_remote();
181 | $this->assertEquals( 'origin', $remote );
182 | }
183 |
184 | /**
185 | * Tests the Revisr_Git::get_commit_details() method.
186 | */
187 | function test_get_commit_details() {
188 | $commit = Revisr_Git::get_commit_details( 'abc1234' );
189 | $this->assertArrayHasKey( 'hash', $commit );
190 | $this->assertArrayHasKey( 'branch', $commit );
191 | $this->assertArrayHasKey( 'author', $commit );
192 | $this->assertArrayHasKey( 'subject', $commit );
193 | $this->assertArrayHasKey( 'time', $commit );
194 | $this->assertArrayHasKey( 'files_changed', $commit );
195 | $this->assertArrayHasKey( 'committed_files', $commit );
196 | $this->assertArrayHasKey( 'tag', $commit );
197 | $this->assertArrayHasKey( 'status', $commit );
198 | }
199 |
200 | /**
201 | * Tests the get_status() method.
202 | */
203 | function test_get_status() {
204 | $test_modified = Revisr_Git::get_status( 'MM' );
205 | $test_deleted = Revisr_Git::get_status( 'DD' );
206 | $test_added = Revisr_Git::get_status( 'AA' );
207 | $test_renamed = Revisr_Git::get_status( 'RR' );
208 | $test_untracked = Revisr_Git::get_status( '??' );
209 | $test_invalid = Revisr_Git::get_status( '$$' );
210 |
211 | $this->assertEquals( 'Modified', $test_modified );
212 | $this->assertEquals( 'Deleted', $test_deleted );
213 | $this->assertEquals( 'Added', $test_added );
214 | $this->assertEquals( 'Renamed', $test_renamed );
215 | $this->assertEquals( 'Untracked', $test_untracked );
216 | $this->assertFalse( $test_invalid );
217 |
218 | }
219 |
220 | /**
221 | * Tests the tag() function.
222 | */
223 | function test_tag() {
224 | $time = time();
225 | $this->revisr->git->tag( $time );
226 | $tags = serialize( $this->revisr->git->run( 'tag', array() ) );
227 | $this->assertContains( "$time", $tags );
228 | $this->revisr->git->run( 'tag', array( '-d', $time ) );
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/tests/test-remote.php:
--------------------------------------------------------------------------------
1 | remote = new Revisr_Remote();
10 | }
11 |
12 | /**
13 | * Tests the "get_token()" method.
14 | */
15 | function test_get_token() {
16 | $token = $this->remote->get_token();
17 |
18 | if ( is_string( $token ) && strlen( $token ) === 16 ) {
19 | $result = true;
20 | } else {
21 | $result = false;
22 | }
23 |
24 | $this->assertTrue( $result );
25 | }
26 |
27 | /**
28 | * Tests the "check_token()" method.
29 | */
30 | function test_check_token() {
31 | $token = $this->remote->get_token();
32 | $result = $this->remote->check_token( $token );
33 | $this->assertTrue( $result );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/test-revisr.php:
--------------------------------------------------------------------------------
1 | revisr = revisr();
15 | }
16 |
17 | /**
18 | * Tests the revisr() method.
19 | */
20 | function test_revisr() {
21 | revisr();
22 | $this->assertClassHasStaticAttribute( 'instance', 'Revisr' );
23 | }
24 |
25 | /**
26 | * Tests the define_constants() method.
27 | */
28 | function test_define_constants() {
29 | // Plugin Folder URL
30 | $path = str_replace( 'tests/', '', plugin_dir_url( __FILE__ ) );
31 | $this->assertSame( REVISR_URL, $path );
32 |
33 | // Plugin Folder Path
34 | $path = str_replace( 'tests/', '', plugin_dir_path( __FILE__ ) );
35 | $this->assertSame( REVISR_PATH, $path );
36 |
37 | // Plugin Root File
38 | $path = str_replace( 'tests/', '', plugin_dir_path( __FILE__ ) );
39 | $this->assertSame( REVISR_FILE, $path . 'revisr.php' );
40 | }
41 |
42 | /**
43 | * Tests the load_dependencies() method.
44 | */
45 | function test_load_dependencies() {
46 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-activity-table.php' );
47 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-admin.php' );
48 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-admin-pages.php' );
49 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-branch-table.php' );
50 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-commits-table.php' );
51 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-meta-boxes.php' );
52 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-compatibility.php' );
53 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-cron.php' );
54 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-db-backup.php' );
55 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-db-import.php' );
56 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-db.php' );
57 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-git-callback.php' );
58 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-git.php' );
59 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-i18n.php' );
60 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-process.php' );
61 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-remote.php' );
62 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-settings-fields.php' );
63 | $this->assertFileExists( REVISR_PATH . 'classes/class-revisr-settings.php' );
64 | }
65 |
66 | /**
67 | * Tests get_table_name().
68 | */
69 | function test_get_table_name() {
70 | $revisr_table_name = Revisr::get_table_name();
71 | $this->assertContains( 'revisr', $revisr_table_name );
72 | }
73 |
74 | /**
75 | * Tests the get_options() method.
76 | */
77 | function test_get_options() {
78 | $options = Revisr::get_options();
79 | if ( is_array( $options ) ) {
80 | $result = true;
81 | } else {
82 | $result = false;
83 | }
84 | $this->assertTrue( $result );
85 | }
86 |
87 | /**
88 | * Tests the database installation.
89 | */
90 | function test_install() {
91 | Revisr::install();
92 | global $wpdb;
93 | $table_name = $wpdb->prefix . 'revisr';
94 | $table_check = $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" );
95 | $this->assertEquals( $table_name, $table_check );
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/uninstall.php:
--------------------------------------------------------------------------------
1 | options['uninstall_on_delete'] ) {
20 |
21 | // Remove any set crons.
22 | wp_clear_scheduled_hook( 'revisr_cron' );
23 |
24 | // Remove any set options.
25 | delete_option( 'revisr_settings' );
26 | delete_option( 'revisr_general_settings' );
27 | delete_option( 'revisr_remote_settings' );
28 | delete_option( 'revisr_database_settings' );
29 |
30 | // Remove any set transients.
31 | delete_transient( 'revisr_error_details' );
32 | delete_transient( 'revisr_error' );
33 | delete_transient( 'revisr_alert' );
34 | delete_transient( 'revisr_skip_setup' );
35 |
36 | // Delete any commits.
37 | $commits = get_posts( array( 'post_type' => 'revisr_commits', 'post_status' => 'any', 'number_posts' => -1, 'fields' => 'ids' ) );
38 | foreach ( $commits as $commit ) {
39 | wp_delete_post( $commit, true );
40 | }
41 |
42 | // Drop the Revisr database table.
43 | global $wpdb;
44 | $table_name = $wpdb->prefix . 'revisr';
45 | $sql = "DROP TABLE $table_name";
46 | $wpdb->query( $sql );
47 |
48 | }
49 |
--------------------------------------------------------------------------------