Compare commits
208 Commits
Author | SHA1 | Date |
---|---|---|
dependabot[bot] | 8bf1947809 | |
dependabot[bot] | 302057a80c | |
dependabot[bot] | a0349be6d1 | |
dependabot[bot] | f46701573f | |
dependabot[bot] | 6373ea90a1 | |
dependabot[bot] | 9fa27cccd2 | |
Garion Herman | 6e7a7f15f1 | |
dependabot[bot] | 04a81b6bb9 | |
dependabot[bot] | d4562c381e | |
dependabot[bot] | b638e43348 | |
dependabot[bot] | 4a11c7c0c7 | |
dependabot[bot] | f3c1614aea | |
Aaron Carlino | 42540b6a10 | |
Aaron Carlino | 85dce59716 | |
Steve Boyd | 9f23ed4769 | |
Steve Boyd | 3b21e4cf88 | |
Serge Latyntsev | 37c79d257a | |
Serge Latyntsev | 6c1fcf6266 | |
Serge Latyntcev | 402dc77ed6 | |
Steve Boyd | 209737c4b6 | |
Steve Boyd | a09499b4bd | |
Maxime Rainville | 09fea7961e | |
Steve Boyd | e2dc05b0ff | |
Aaron Carlino | 9cf74f57c2 | |
Maxime Rainville | f2ef1b82ea | |
Maxime Rainville | 8aba8cd8d7 | |
Maxime Rainville | 49239899fa | |
Loz Calver | 945119a1da | |
Robbie Averill | e7535a6af6 | |
Loz Calver | 1fc11a7854 | |
Robbie Averill | 63b6fa567a | |
James Ayers | 42275f5d13 | |
Daniel Hensby | c0fbe98851 | |
Dave Collins | cf278fd8e2 | |
Dave Collins | 52772ae879 | |
Dave Collins | 5561e4a7af | |
Dave Collins | 71c09244f7 | |
Robbie Averill | d94aa25ac7 | |
Ian Walls | dfbddb49a2 | |
Robbie Averill | 4f5dddc17d | |
Dylan Wagstaff | 6d36c67195 | |
Robbie Averill | eb85a86296 | |
Dylan Wagstaff | 95d37b282d | |
Dylan Wagstaff | 86bc9ec509 | |
Dylan Wagstaff | fad86bd93c | |
Florian Thoma | 1c226239f4 | |
Florian Thoma | 86e01cb6d1 | |
Florian Thoma | 2c204bb0b6 | |
Robbie Averill | eb96f4fd87 | |
Robbie Averill | fb6bdf59c2 | |
Florian Thoma | f36b439f8f | |
Robbie Averill | b5f9602eb5 | |
Robbie Averill | 35423c9aeb | |
Robbie Averill | 96bac3fdc9 | |
Robbie Averill | 046047e49f | |
Robbie Averill | ab9d361f98 | |
Robbie Averill | b7a3a1df6e | |
Damian Mooyman | bcf2ac9757 | |
Robbie Averill | 8efedf3158 | |
Dylan Wagstaff | 82a8a4b142 | |
Dylan Wagstaff | b7aaadf7bb | |
Robbie Averill | 0e84799f59 | |
Robbie Averill | 854d1f9150 | |
Robbie Averill | 1bceff58dd | |
Robbie Averill | 99ee72e17f | |
Robbie Averill | eeca59f190 | |
Robbie Averill | 14b615f1e4 | |
Raissa North | 0d27e614cd | |
Franco Springveldt | 45092dfb16 | |
Robbie Averill | 2922e83dc1 | |
Mateusz Qunabu | a61d294419 | |
Robbie Averill | ee9d2dfb58 | |
Franco Springveldt | 16f0bef034 | |
Robbie Averill | 5efe1a4a87 | |
Robbie Averill | 6a67cddc38 | |
Robbie Averill | 77f137fcda | |
Robbie Averill | b2c16477d1 | |
Robbie Averill | 97d55603d6 | |
Robbie Averill | 6c5e70dc33 | |
Robbie Averill | b9b7be0417 | |
Florian Thoma | 9b31a7071f | |
Florian Thoma | f41375e608 | |
Robbie Averill | f9f56b0ef2 | |
Franco Springveldt | 1fd287b264 | |
Robbie Averill | d38e493925 | |
Robbie Averill | ac5a01614b | |
Florian Thoma | 0338425cbc | |
Robbie Averill | 06692ee4ae | |
sachajudd | 9d117d6f49 | |
Franco Springveldt | e2eead8888 | |
Robbie Averill | a5ffec88bd | |
Robbie Averill | 31b3fff74e | |
Robbie Averill | 1e8ac1fee8 | |
Daniel Hensby | 6db701104c | |
Daniel Hensby | b4e5c29a04 | |
Sacha Judd | 54b9b0b8ea | |
Robbie Averill | 0d1e57eec6 | |
Robbie Averill | e5c7d1aa9a | |
Sacha Judd | 8518739a13 | |
Daniel Hensby | d001a9a780 | |
Robbie Averill | 4ba3e3fa60 | |
Franco Springveldt | 4bdeb980d9 | |
Robbie Averill | 9d5e028d10 | |
Robbie Averill | d57fc88bfa | |
Franco Springveldt | 79da01513e | |
Robbie Averill | d0c2558a1f | |
sachajudd | 4d83b95040 | |
Robbie Averill | a76b1d0256 | |
sachajudd | ed32ce949e | |
Robbie Averill | 1f7b17a2d3 | |
sachajudd | 98c20aa4dd | |
Robbie Averill | e85e13123e | |
Robbie Averill | 72873608c4 | |
Sacha Judd | c10109b49b | |
sachajudd | b0de8b33e5 | |
Robbie Averill | 772198a7fc | |
sachajudd | c0dee2f1e5 | |
Robbie Averill | 14071eee3c | |
Robbie Averill | 6b63f738d7 | |
Daniel Hensby | bacc3db4ef | |
Robbie Averill | edf2266326 | |
Robbie Averill | 4c3206e200 | |
Robbie Averill | 5d7479013e | |
Robbie Averill | 832eb14fad | |
sachajudd | 55ee260cba | |
Franco Springveldt | ce37b81c2b | |
sachajudd | 0368293e74 | |
Franco Springveldt | 5824c1b0eb | |
Franco Springveldt | 19eca581cc | |
sachajudd | 5bea2fb5f1 | |
Robbie Averill | f6fda3b241 | |
Robbie Averill | f296c89dc0 | |
sachajudd | 84c7233b79 | |
sachajudd | 8208822400 | |
Robbie Averill | 58ac37a1e8 | |
Robbie Averill | 8a7fe273a6 | |
sachajudd | 46aafb1df6 | |
Robbie Averill | 7fb2662958 | |
Robbie Averill | d8f3685601 | |
Sacha Judd | cbd3a65fa9 | |
Robbie Averill | d3cd151ebc | |
Franco Springveldt | 3d19b9fc75 | |
Franco Springveldt | 886fd217f2 | |
Robbie Averill | e95182f8fc | |
Sacha Judd | 9200d83b12 | |
sachajudd | a0ef0dc437 | |
Robbie Averill | c7c4a356eb | |
Sacha Judd | aedc970cf4 | |
Robbie Averill | d95b98d10d | |
Robbie Averill | cbc53fd7d2 | |
sachajudd | 11819a1e16 | |
sachajudd | 5c8aeb0c58 | |
Robbie Averill | 0ffd4d8584 | |
Robbie Averill | 80e36c3350 | |
sachajudd | 2ddd20cd6c | |
Robbie Averill | 9b42effeb5 | |
Franco Springveldt | e8d46a90a5 | |
Robbie Averill | 489a62abb2 | |
Robbie Averill | 17d97d65ce | |
sachajudd | e4ab2b0861 | |
sachajudd | 6afab52a09 | |
sachajudd | 84abd5d837 | |
Robbie Averill | 283f9fff7a | |
Robbie Averill | 5cb92ecd7c | |
Franco Springveldt | 03fe480ca5 | |
Robbie Averill | 84e1d3ff80 | |
sachajudd | fb989de12b | |
Robbie Averill | 708721a5aa | |
sachajudd | 2039d72688 | |
Robbie Averill | 8d2f707f48 | |
Robbie Averill | a6743b03f5 | |
Robbie Averill | 961306ecc0 | |
Franco Springveldt | e08e276e89 | |
Franco Springveldt | 6b25237ec6 | |
Franco Springveldt | f506fb7247 | |
Sacha Judd | e1e5194c1c | |
sachajudd | 6b80f32832 | |
sachajudd | a59349e37f | |
sachajudd | b42d446480 | |
Robbie Averill | a376b3480a | |
Robbie Averill | 513c29aa99 | |
Robbie Averill | 5858511078 | |
Robbie Averill | aafcc35f6c | |
sachajudd | ed6f805574 | |
Robbie Averill | 1c1b1d2aeb | |
Robbie Averill | 66abd22ee5 | |
Robbie Averill | b80aa645f8 | |
Robbie Averill | e4bc553521 | |
sachajudd | 9c5693dab0 | |
Robbie Averill | 2329ba4f40 | |
sachajudd | a6aa575501 | |
Franco Springveldt | 8682c7fca9 | |
Franco Springveldt | 38501542ee | |
Sacha Judd | d29a115f7b | |
Franco Springveldt | 1f07069363 | |
Franco Springveldt | b0ab198fc4 | |
Franco Springveldt | bbe9e35d99 | |
Robbie Averill | 0b691b4f13 | |
Robbie Averill | cef27febf6 | |
Robbie Averill | 9c0ec616d1 | |
Robbie Averill | e5f1b5c9db | |
Franco Springveldt | 2e2112a3b5 | |
Franco Springveldt | 1d2defe0cc | |
Robbie Averill | 499ddebedf | |
Franco Springveldt | bc130b3f1c | |
Robbie Averill | ea587ee645 | |
Robbie Averill | 04188816c6 | |
Robbie Averill | 39ce206b55 |
|
@ -0,0 +1 @@
|
|||
comment: off
|
|
@ -10,7 +10,7 @@ indent_style = space
|
|||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.yml,package.json}]
|
||||
[{*.yml,package.json,*.scss,*.js}]
|
||||
indent_size = 2
|
||||
|
||||
# The indent size used in the package.json file cannot be changed:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/docs export-ignore
|
||||
/tests export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.travis.yml export-ignore
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
name: Build Docs
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
paths:
|
||||
- 'docs/en/userguide/**'
|
||||
jobs:
|
||||
build:
|
||||
name: build-docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run build hook
|
||||
run: curl -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_BUILD_HOOK }}
|
|
@ -1,2 +1,2 @@
|
|||
.sass-cache
|
||||
.DS_Store
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
|
|
54
.travis.yml
|
@ -1,37 +1,45 @@
|
|||
# See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details
|
||||
|
||||
sudo: false
|
||||
# See https://github.com/silverstripe/silverstripe-travis-support for setup details
|
||||
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
- DB=MYSQL CORE_RELEASE=3.2
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.6
|
||||
env: DB=MYSQL CORE_RELEASE=3
|
||||
- php: 5.6
|
||||
env: DB=MYSQL CORE_RELEASE=3.1
|
||||
- php: 5.6
|
||||
env: DB=MYSQL CORE_RELEASE=3.3
|
||||
- php: 5.6
|
||||
env: DB=MYSQL CORE_RELEASE=3.4
|
||||
- php: 5.6
|
||||
env: DB=MYSQL CORE_RELEASE=3.5
|
||||
env: DB=MYSQL CORE_RELEASE=3.6
|
||||
- php: 7.1
|
||||
env: DB=MYSQL CORE_RELEASE=3.7
|
||||
- php: 7.2
|
||||
env: DB=MYSQL CORE_RELEASE=3.7 NPM_TEST=1
|
||||
- php: 7.3
|
||||
env: DB=MYSQL CORE_RELEASE=3.7 COVERAGE="--coverage-clover=coverage.xml"
|
||||
|
||||
before_script:
|
||||
- echo -e "[server]\nmax_allowed_packet=64M" | sudo tee -a /etc/mysql/conf.d/dms.cnf
|
||||
- sudo service mysql restart
|
||||
- composer self-update || true
|
||||
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support
|
||||
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss
|
||||
- cd ~/builds/ss
|
||||
- git clone git://github.com/silverstripe/silverstripe-travis-support.git ~/travis-support
|
||||
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/build/ss --require undefinedoffset/sortablegridfield:~0.6.9
|
||||
- cd ~/build/ss
|
||||
- composer install
|
||||
- if [[ $NPM_TEST ]]; then npm install -g yarn && yarn install --network-concurrency 1; fi
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit dms/tests
|
||||
- vendor/bin/phpunit "$COVERAGE" dms/tests
|
||||
- if [[ $NPM_TEST ]]; then cd dms; fi
|
||||
- if [[ $NPM_TEST ]]; then yarn install --production=false; fi
|
||||
- if [[ $NPM_TEST ]]; then yarn run build; fi
|
||||
- if [[ $NPM_TEST ]]; then git diff-files --quiet -w --relative=client; fi
|
||||
- if [[ $NPM_TEST ]]; then git diff --name-status --relative=client; fi
|
||||
- if [[ $NPM_TEST ]]; then cd ..; fi
|
||||
|
||||
after_success:
|
||||
- >
|
||||
test "$COVERAGE" != ""
|
||||
&& mv coverage.xml ~/build/$TRAVIS_REPO_SLUG
|
||||
&& cd ~/build/$TRAVIS_REPO_SLUG
|
||||
&& bash <(curl -s https://codecov.io/bash)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# Contributing
|
||||
|
||||
Any open source product is only as good as the community behind it. You can participate by sharing code, ideas, or simply helping others. No matter what your skill level is, every contribution counts.
|
||||
|
||||
See our [high level overview](http://silverstripe.org/contributing-to-silverstripe) on silverstripe.org on how you can help out.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2017, SilverStripe Ltd.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of silverstripe-cms nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
122
README.md
|
@ -1,131 +1,43 @@
|
|||
# Document Management Module (DMS)
|
||||
|
||||
[![Build Status](https://travis-ci.org/silverstripe/silverstripe-dms.png?branch=master)](https://travis-ci.org/silverstripe/silverstripe-dms)
|
||||
[![Build status](https://travis-ci.org/silverstripe/silverstripe-dms.png?branch=master)](https://travis-ci.org/silverstripe/silverstripe-dms)
|
||||
[![SilverStripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
|
||||
[![Code quality](https://scrutinizer-ci.com/g/silverstripe/silverstripe-dms/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/silverstripe/silverstripe-dms/?branch=master)
|
||||
[![Code coverage](https://codecov.io/gh/silverstripe/silverstripe-dms/branch/master/graph/badge.svg)](https://codecov.io/gh/silverstripe/silverstripe-dms)
|
||||
![Helpful Robot](https://img.shields.io/badge/helpfulrobot-52-yellow.svg?style=flat)
|
||||
|
||||
## Overview
|
||||
|
||||
The module adds a new `DMSDocument` model which allows management
|
||||
of large amounts of files, and their relations to pages.
|
||||
In contrast to the `File` model built into SilverStripe core,
|
||||
it aims to wrap storage and access concerns in a generic API,
|
||||
which allows more fine-grained control over how the documents are
|
||||
managed and exposed through the website.
|
||||
The module adds a new `DMSDocument` model which allows management of large amounts of files, and their relations to
|
||||
pages. In contrast to the `File` model built into SilverStripe core, it aims to wrap storage and access concerns in
|
||||
a generic API. This allows more fine-grained control over how the documents are managed and exposed through the website.
|
||||
|
||||
Additionally, documents are stored and managed as part of a page instead of
|
||||
away in a separate assets store.
|
||||
Additionally, documents are stored and managed as part of a page instead of away in a separate assets store.
|
||||
|
||||
Read more about the DMS module in this [blog post on silverstripe.org](http://www.silverstripe.org/document-management-system-module)
|
||||
|
||||
Features:
|
||||
## Features
|
||||
|
||||
* Relation of documents to pages
|
||||
* Relation of documents to other documents
|
||||
* Management and upload of documents within a page context in the CMS
|
||||
* Metadata management through the powerful `GridField` and `UploadField` core APIs
|
||||
* Configurable tags for documents
|
||||
* Download via SilverStripe controller (rather than filesystem URLs)
|
||||
* Access control based on PHP logic, and page relations
|
||||
* Replacement of existing files
|
||||
* Tagging via the [taxonomy module](https://github.com/silverstripe/silverstripe-taxonomy) if installed
|
||||
|
||||
## Documents on the Filesystem
|
||||
## Documentation
|
||||
|
||||
While the DMS architecture allows for remote storage of files,
|
||||
the default implementation (the `DMS` class) stores them locally.
|
||||
Relations to pages and tags are persisted as many-many relationships
|
||||
through the SilverStripe ORM.
|
||||
For information on configuring and using this module, please see [the documentation section](docs/en/index.md).
|
||||
|
||||
File locations in this implementation are structured into
|
||||
subfolders, in order to avoid exceeding filesystem limits.
|
||||
The file name is a composite based on its database ID
|
||||
and the original file name. The exact location shouldn't
|
||||
be relied on by custom logic, but rather retrieved through
|
||||
the API (`DMSDocument->getLink()`).
|
||||
|
||||
Example:
|
||||
|
||||
dms-assets/
|
||||
0/
|
||||
1234~myfile.pdf
|
||||
1/
|
||||
2345~myotherfile.pdf
|
||||
|
||||
|
||||
### Requirements
|
||||
## Requirements
|
||||
|
||||
* PHP 5.3 with the "fileinfo" module (or alternatively the "whereis" and "file" Unix commands)
|
||||
* SilverStripe framework/CMS ^3.5
|
||||
* [Taxonomy](https://github.com/silverstripe/silverstripe-taxonomy) ^1.2 (for tagging)
|
||||
* (optional) [Pagination of Documents in the CMS](https://github.com/silverstripe-big-o/gridfieldpaginatorwithshowall)
|
||||
* (optional) [Sorting of Documents in the CMS](https://github.com/silverstripe-big-o/SortableGridField)
|
||||
* (optional) [Full text search of Documents](https://github.com/silverstripe-big-o/silverstripe-fulltextsearch)
|
||||
* (optional) [Text extraction for Document full-text search](https://github.com/silverstripe-big-o/silverstripe-textextraction)
|
||||
* (optional) [Tags](https://github.com/tubbs/silverstripe-dms-simple-tags)
|
||||
|
||||
### Configuration
|
||||
|
||||
The file location is set via the `DMS::$dmsFolder` static, and points to a location in the webroot.
|
||||
|
||||
### Usage
|
||||
|
||||
Add a simple include to any of your .ss templates to display the DMSDocuments associated with
|
||||
the current page on the front-end.
|
||||
|
||||
<% include Documents %>
|
||||
|
||||
#### Create Documents
|
||||
|
||||
Create by relative path:
|
||||
|
||||
$dms = DMS::getDMSInstance();
|
||||
$doc = $dms->storeDocument('assets/myfile.pdf');
|
||||
|
||||
Create from an existing `File` record:
|
||||
|
||||
$dms = DMS::getDMSInstance();
|
||||
$file = File::get()->byID(99);
|
||||
$doc = $dms->storeDocument($file);
|
||||
|
||||
Note: Both operations copy the existing file.
|
||||
|
||||
#### Download Documents
|
||||
|
||||
$dms = DMS::getDMSInstance();
|
||||
$docs = $dms->getByTag('priority', 'important')->First();
|
||||
$link = $doc->getLink();
|
||||
|
||||
// Set default download behavior ('open' or 'download'). 'download' is the system default
|
||||
// Attempt to open the file in the browser
|
||||
Config::inst()->update('DMSDocument', 'default_download_behaviour', 'open');
|
||||
|
||||
Or in you config.yml:
|
||||
|
||||
DMSDocument:
|
||||
default_download_behaviour: open
|
||||
|
||||
#### Manage Page Relations
|
||||
|
||||
// Find documents by page
|
||||
$dms = DMS::getDMSInstance();
|
||||
$page = SiteTree::get()->filter('URLSegment', 'home')->First();
|
||||
$docs = $dms->getByPage($page);
|
||||
|
||||
// Add documents to page
|
||||
|
||||
#### Manage Tags
|
||||
|
||||
// Find documents by tag
|
||||
$dms = DMS::getDMSInstance();
|
||||
$docs = $dms->getByTag('priority', 'important');
|
||||
|
||||
// Add tag to existing document
|
||||
$doc = Document::get()->byID(99);
|
||||
$doc->addTag('priority', 'low');
|
||||
|
||||
// Supports multiple values for tags
|
||||
$doc->addTag('category', 'keyboard');
|
||||
$doc->addTag('category', 'input device');
|
||||
|
||||
// Removing tags is abstracted as well
|
||||
$doc->removeTag('category', 'keyboard');
|
||||
$doc->removeTag('category', 'input device');
|
||||
$doc->removeAllTags();
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
25
_config.php
|
@ -2,21 +2,30 @@
|
|||
|
||||
$config = Config::inst();
|
||||
|
||||
DMSSiteTreeExtension::show_documents_tab(); //show the Documents tab on all pages
|
||||
DMSSiteTreeExtension::no_documents_tab(); //and don't exclude it from any pages
|
||||
DMSDocumentAddController::add_allowed_extensions(); //add an array of additional allowed extensions
|
||||
define('DMS_DIR', basename(__DIR__));
|
||||
|
||||
define('DMS_DIR', 'dms');
|
||||
if (!file_exists(BASE_PATH . DIRECTORY_SEPARATOR . DMS_DIR)) {
|
||||
user_error('DMS directory named incorrectly. Please install the DMS module into a folder named: ' . DMS_DIR);
|
||||
}
|
||||
|
||||
if (!file_exists(BASE_PATH . DIRECTORY_SEPARATOR . DMS_DIR)) user_error("DMS directory named incorrectly. Please install the DMS module into a folder named: ".DMS_DIR);
|
||||
// Ensure compatibility with PHP 7.2 ("object" is a reserved word),
|
||||
// with SilverStripe 3.6 (using Object) and SilverStripe 3.7 (using SS_Object)
|
||||
if (!class_exists('SS_Object')) class_alias('Object', 'SS_Object');
|
||||
|
||||
CMSMenu::remove_menu_item('DMSDocumentAddController');
|
||||
|
||||
ShortcodeParser::get('default')->register(
|
||||
'dms_document_link', array('DMSShortcodeHandler', 'handle')
|
||||
$config->get('DMS', 'shortcode_handler_key'),
|
||||
array('DMSShortcodeHandler', 'handle')
|
||||
);
|
||||
|
||||
if ($config->get('DMSDocument_versions', 'enable_versions')) {
|
||||
//using the same db relations for the versioned documents, as for the actual documents
|
||||
$config->update('DMSDocument_versions', 'db', $config->get('DMSDocument', 'db'));
|
||||
//using the same db relations for the versioned documents, as for the actual documents
|
||||
$config->update('DMSDocument_versions', 'db', $config->get('DMSDocument', 'db'));
|
||||
}
|
||||
|
||||
// add dmsassets folder to file system sync exclusion
|
||||
if (strpos($config->get('DMS', 'folder_name'), 'assets/') === 0) {
|
||||
$folderName = substr($config->get('DMS', 'folder_name'), 7);
|
||||
$config->update('Filesystem', 'sync_blacklisted_patterns', array("/^" . $folderName . "$/i",));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
Name: dmsconfig
|
||||
---
|
||||
SiteTree:
|
||||
extensions:
|
||||
- DMSSiteTreeExtension
|
||||
# Whether to show the document sets tab in the CMS for the page type this extension is applied to
|
||||
documents_enabled: true
|
||||
|
||||
HtmlEditorField_Toolbar:
|
||||
extensions:
|
||||
- DocumentHtmlEditorFieldToolbar
|
||||
|
||||
# Ensure that if the parent UploadField is overloaded with the injector, that the DMSUploadField is returned
|
||||
Injector:
|
||||
DMSUploadField: DMSUploadField
|
|
@ -5,11 +5,6 @@ After: framework/routes#coreroutes
|
|||
Director:
|
||||
rules:
|
||||
'dmsdocument/$ID' : 'DMSDocument_Controller'
|
||||
SiteTree:
|
||||
extensions:
|
||||
- DMSSiteTreeExtension
|
||||
HtmlEditorField_Toolbar:
|
||||
extensions:
|
||||
- DocumentHtmlEditorFieldToolbar
|
||||
|
||||
DMSDocument_versions:
|
||||
enable_versions: true
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
DMSDocument:
|
||||
searchable_fields:
|
||||
Title:
|
||||
title: Document title matches
|
||||
Description:
|
||||
title: Document summary matches
|
||||
CreatedByID:
|
||||
title: Document created by
|
||||
field: ListboxField
|
||||
filter: ExactMatchFilter
|
||||
LastEditedByID:
|
||||
title: Document last changed by
|
||||
field: ListboxField
|
||||
filter: ExactMatchFilter
|
||||
Filename:
|
||||
title: File name
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
Name: dmstaxonomy
|
||||
Only:
|
||||
moduleexists: taxonomy
|
||||
---
|
||||
TaxonomyType:
|
||||
extensions:
|
||||
- DMSTaxonomyTypeExtension
|
||||
|
||||
DMSDocument:
|
||||
extensions:
|
||||
- DMSDocumentTaxonomyExtension
|
||||
# Add query builder filter for tags
|
||||
searchable_fields:
|
||||
Tags.ID:
|
||||
title: Document has tags
|
||||
field: ListboxField
|
||||
filter: ExactMatchFilter
|
||||
|
||||
DMSTaxonomyTypeExtension:
|
||||
# Referenced to filter taxonomy terms for DMS Documents.
|
||||
# To change, update the default_records array too.
|
||||
default_record_name: Document
|
||||
default_records:
|
||||
- Document
|
166
code/DMS.php
|
@ -1,42 +1,91 @@
|
|||
<?php
|
||||
class DMS implements DMSInterface
|
||||
class DMS extends SS_Object implements DMSInterface
|
||||
{
|
||||
/**
|
||||
* Folder to store the documents in
|
||||
*
|
||||
* @config
|
||||
* @var string
|
||||
*/
|
||||
private static $folder_name = 'assets/_dmsassets';
|
||||
|
||||
public static $dmsFolder = 'dms-assets'; //folder to store the documents in
|
||||
/**
|
||||
* How many documents to store in a single folder. The square of this number is the maximum number of documents.
|
||||
*
|
||||
* The number should be a multiple of 10
|
||||
*
|
||||
* @config
|
||||
* @var int
|
||||
*/
|
||||
private static $folder_size = 1000;
|
||||
|
||||
//How many documents to store in a single folder. The square of this number is the maximum number of documents.
|
||||
//The number should be a multiple of 10
|
||||
public static $dmsFolderSize = 1000;
|
||||
/**
|
||||
* Singleton instance of a DMSInterface
|
||||
*
|
||||
* @var DMSInterface
|
||||
*/
|
||||
private static $instance;
|
||||
|
||||
/**
|
||||
* The shortcode handler key. Can be changed by user code.
|
||||
*
|
||||
* @config
|
||||
* @var string
|
||||
*/
|
||||
private static $shortcode_handler_key = 'dms_document_link';
|
||||
|
||||
/**
|
||||
* Factory method that returns an instance of the DMS. This could be any class that implements the DMSInterface.
|
||||
* @static
|
||||
*
|
||||
* @return DMSInterface An instance of the Document Management System
|
||||
*/
|
||||
public static function inst()
|
||||
{
|
||||
$dmsPath = self::get_dms_path();
|
||||
if (!self::$instance) {
|
||||
self::$instance = new static();
|
||||
|
||||
$dms = new DMS();
|
||||
if (!is_dir($dmsPath)) {
|
||||
self::create_storage_folder($dmsPath);
|
||||
}
|
||||
$dmsPath = self::$instance->getStoragePath();
|
||||
|
||||
if (!file_exists($dmsPath . DIRECTORY_SEPARATOR . '.htaccess')) {
|
||||
//restrict access to the storage folder
|
||||
copy(BASE_PATH . DIRECTORY_SEPARATOR . DMS_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . '.htaccess', $dmsPath . DIRECTORY_SEPARATOR . '.htaccess');
|
||||
copy(BASE_PATH . DIRECTORY_SEPARATOR . DMS_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'web.config', $dmsPath . DIRECTORY_SEPARATOR . 'web.config');
|
||||
if (!is_dir($dmsPath)) {
|
||||
self::$instance->createStorageFolder($dmsPath);
|
||||
}
|
||||
|
||||
if (!file_exists($dmsPath . DIRECTORY_SEPARATOR . '.htaccess')) {
|
||||
// Restrict access to the storage folder
|
||||
copy(
|
||||
BASE_PATH . DIRECTORY_SEPARATOR . DMS_DIR . DIRECTORY_SEPARATOR
|
||||
. 'resources' . DIRECTORY_SEPARATOR . '.htaccess',
|
||||
$dmsPath . DIRECTORY_SEPARATOR . '.htaccess'
|
||||
);
|
||||
|
||||
copy(
|
||||
BASE_PATH . DIRECTORY_SEPARATOR . DMS_DIR . DIRECTORY_SEPARATOR
|
||||
. 'resources' . DIRECTORY_SEPARATOR . 'web.config',
|
||||
$dmsPath . DIRECTORY_SEPARATOR . 'web.config'
|
||||
);
|
||||
}
|
||||
}
|
||||
return $dms;
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public static function get_dms_path()
|
||||
/**
|
||||
* Get the storage path for DMS documents
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getStoragePath()
|
||||
{
|
||||
return BASE_PATH . DIRECTORY_SEPARATOR . self::$dmsFolder;
|
||||
return BASE_PATH . DIRECTORY_SEPARATOR . $this->config()->get('folder_name');
|
||||
}
|
||||
|
||||
public static function transform_file_to_file_path($file)
|
||||
/**
|
||||
* Gets a file path from either a File or a string
|
||||
*
|
||||
* @param string|File $file
|
||||
* @return string
|
||||
* @throws FileNotFoundException If an unexpected value was provided, or the filename was null
|
||||
*/
|
||||
public function transformFileToFilePath($file)
|
||||
{
|
||||
//confirm we have a file
|
||||
$filePath = null;
|
||||
|
@ -56,35 +105,22 @@ class DMS implements DMSInterface
|
|||
/**
|
||||
* Takes a File object or a String (path to a file) and copies it into the DMS. The original file remains unchanged.
|
||||
* When storing a document, sets the fields on the File has "tag" metadata.
|
||||
* @param $file File object, or String that is path to a file to store, e.g. "assets/documents/industry/supplied-v1-0.pdf"
|
||||
|
||||
* @param File|string $file File object, or String that is path to a file to store,
|
||||
* e.g. "assets/documents/industry/supplied-v1-0.pdf"
|
||||
* @return DMSDocument
|
||||
*/
|
||||
public function storeDocument($file)
|
||||
{
|
||||
$filePath = self::transform_file_to_file_path($file);
|
||||
|
||||
//create a new document and get its ID
|
||||
$doc = new DMSDocument();
|
||||
$filePath = $this->transformFileToFilePath($file);
|
||||
|
||||
// Create a new document and get its ID
|
||||
$doc = DMSDocument::create();
|
||||
$doc->write();
|
||||
$doc->storeDocument($filePath);
|
||||
|
||||
return $doc;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns a number of Document objects based on the a search by tags. You can search by category alone,
|
||||
* by tag value alone, or by both. I.e: getByTag("fruits",null); getByTag(null,"banana"); getByTag("fruits","banana")
|
||||
* @param null $category The metadata category to search for
|
||||
* @param null $value The metadata value to search for
|
||||
* @param bool $showEmbargoed Boolean that specifies if embargoed documents should be included in results
|
||||
* @return DocumentInterface
|
||||
*/
|
||||
public function getByTag($category = null, $value = null, $showEmbargoed = false)
|
||||
{
|
||||
// TODO: Implement getByTag() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number of Document objects that match a full-text search of the Documents and their contents
|
||||
* (if contents is searchable and compatible search module is installed - e.g. FullTextSearch module)
|
||||
|
@ -97,34 +133,58 @@ class DMS implements DMSInterface
|
|||
// TODO: Implement getByFullTextSearch() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of Document objects associated with a Page
|
||||
* @param $page SiteTree to fetch the associated Documents from
|
||||
* @param bool $showEmbargoed Boolean that specifies if embargoed documents should be included in results
|
||||
* @return DataList Document list associated with the Page
|
||||
*/
|
||||
public function getByPage($page, $showEmbargoed = false)
|
||||
public function getByPage(SiteTree $page, $showEmbargoed = false)
|
||||
{
|
||||
// TODO: Implement getByPage() method.
|
||||
/** @var ArrayList $documents */
|
||||
$documents = $page->getAllDocuments();
|
||||
|
||||
if (!$showEmbargoed) {
|
||||
foreach ($documents as $document) {
|
||||
if ($document->isEmbargoed()) {
|
||||
$documents->remove($document);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $documents;
|
||||
}
|
||||
|
||||
public function getDocumentSetsByPage(SiteTree $page)
|
||||
{
|
||||
return $page->getDocumentSets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a storage folder for the given path
|
||||
* @param $path Path to create a folder for
|
||||
*
|
||||
* @param string $path Path to create a folder for
|
||||
* @return $this
|
||||
*/
|
||||
public static function create_storage_folder($path)
|
||||
public function createStorageFolder($path)
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path, 0777);
|
||||
mkdir($path, 0777, true);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the storage path from a database DMSDocument ID
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_storage_folder($id)
|
||||
public function getStorageFolder($id)
|
||||
{
|
||||
$folderName = intval($id / self::$dmsFolderSize);
|
||||
return $folderName;
|
||||
return intval($id / self::config()->get('folder_size'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shortcode handler key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getShortcodeHandlerKey()
|
||||
{
|
||||
return (string) Config::inst()->get('DMS', 'shortcode_handler_key');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,26 +8,26 @@
|
|||
*/
|
||||
class DMSShortcodeHandler
|
||||
{
|
||||
|
||||
public static function handle(
|
||||
$arguments, $content, ShortcodeParser $parser, $tag, array $extra = array()
|
||||
) {
|
||||
public static function handle($arguments, $content, ShortcodeParser $parser, $tag, array $extra = array())
|
||||
{
|
||||
if (!empty($arguments['id'])) {
|
||||
$document = DMSDocument::get()->byID($arguments['id']);
|
||||
|
||||
if ($document && !$document->isHidden()) {
|
||||
if ($content) {
|
||||
return sprintf(
|
||||
'<a href="%s">%s</a>', $document->Link(), $parser->parse($content)
|
||||
'<a href="%s">%s</a>',
|
||||
$document->Link(),
|
||||
$parser->parse($content)
|
||||
);
|
||||
} else {
|
||||
if (isset($extra['element'])) {
|
||||
$extra['element']->setAttribute('data-ext', $document->getExtension());
|
||||
$extra['element']->setAttribute('data-size', $document->getFileSizeFormatted());
|
||||
}
|
||||
|
||||
return $document->Link();
|
||||
}
|
||||
|
||||
if (isset($extra['element'])) {
|
||||
$extra['element']->setAttribute('data-ext', $document->getExtension());
|
||||
$extra['element']->setAttribute('data-size', $document->getFileSizeFormatted());
|
||||
}
|
||||
|
||||
return $document->Link();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,8 @@
|
|||
/**
|
||||
* @package dms
|
||||
*/
|
||||
|
||||
class DMSDocumentAddController extends LeftAndMain
|
||||
{
|
||||
|
||||
private static $url_segment = 'pages/adddocument';
|
||||
private static $url_priority = 60;
|
||||
private static $required_permission_codes = 'CMS_ACCESS_AssetAdmin';
|
||||
|
@ -14,7 +12,13 @@ class DMSDocumentAddController extends LeftAndMain
|
|||
private static $tree_class = 'SiteTree';
|
||||
private static $session_namespace = 'CMSMain';
|
||||
|
||||
public static $allowed_extensions = array();
|
||||
/**
|
||||
* Allowed file upload extensions, will be merged with `$allowed_extensions` from {@link File}
|
||||
*
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $allowed_extensions = array();
|
||||
|
||||
private static $allowed_actions = array(
|
||||
'getEditForm',
|
||||
|
@ -23,48 +27,42 @@ class DMSDocumentAddController extends LeftAndMain
|
|||
'documentlist'
|
||||
);
|
||||
|
||||
/**
|
||||
* Add an array of additional allowed extensions
|
||||
* @static
|
||||
* @param $array
|
||||
*/
|
||||
public static function add_allowed_extensions($array = null)
|
||||
{
|
||||
if (empty($array)) {
|
||||
return;
|
||||
}
|
||||
if (is_array($array)) {
|
||||
self::$allowed_extensions = $array;
|
||||
} else {
|
||||
self::$allowed_extensions = array($array);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom currentPage() method to handle opening the 'root' folder
|
||||
*
|
||||
* @return
|
||||
* @return SiteTree
|
||||
*/
|
||||
public function currentPage()
|
||||
{
|
||||
$id = $this->currentPageID();
|
||||
|
||||
if ($id && is_numeric($id) && $id > 0) {
|
||||
return Versioned::get_by_stage('SiteTree', 'Stage', sprintf(
|
||||
'ID = %s', (int) $id
|
||||
))->first();
|
||||
} else {
|
||||
// ID is either '0' or 'root'
|
||||
return singleton('SiteTree');
|
||||
if ($id === 0) {
|
||||
return SiteTree::singleton();
|
||||
}
|
||||
return parent::currentPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return fake-ID "root" if no ID is found (needed to upload files into the root-folder)
|
||||
* Return fake-ID "root" if no ID is found (needed to upload files into the root-folder). Otherwise the page ID
|
||||
* is passed in from the {@link DMSGridFieldAddNewButton}.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function currentPageID()
|
||||
{
|
||||
return ($result = parent::currentPageID()) === null ? 0 : $result;
|
||||
return (int) $this->getRequest()->getVar('page_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current document set, if a document set ID was provided
|
||||
*
|
||||
* @return DMSDocumentSet
|
||||
*/
|
||||
public function getCurrentDocumentSet()
|
||||
{
|
||||
if ($id = $this->getRequest()->getVar('dsid')) {
|
||||
return DMSDocumentSet::get()->byId($id);
|
||||
}
|
||||
return singleton('DMSDocumentSet');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,9 +73,13 @@ class DMSDocumentAddController extends LeftAndMain
|
|||
{
|
||||
Requirements::javascript(FRAMEWORK_DIR . '/javascript/AssetUploadField.js');
|
||||
Requirements::css(FRAMEWORK_DIR . '/css/AssetUploadField.css');
|
||||
Requirements::css(DMS_DIR.'/css/DMSMainCMS.css');
|
||||
Requirements::css(DMS_DIR . '/dist/css/cmsbundle.css');
|
||||
|
||||
/** @var SiteTree $page */
|
||||
$page = $this->currentPage();
|
||||
/** @var DMSDocumentSet $documentSet */
|
||||
$documentSet = $this->getCurrentDocumentSet();
|
||||
|
||||
$uploadField = DMSUploadField::create('AssetUploadField', '');
|
||||
$uploadField->setConfig('previewMaxWidth', 40);
|
||||
$uploadField->setConfig('previewMaxHeight', 30);
|
||||
|
@ -87,27 +89,32 @@ class DMSDocumentAddController extends LeftAndMain
|
|||
$uploadField->addExtraClass('ss-assetuploadfield');
|
||||
$uploadField->removeExtraClass('ss-uploadfield');
|
||||
$uploadField->setTemplate('AssetUploadField');
|
||||
$uploadField->setRecord($page);
|
||||
$uploadField->setRecord($documentSet);
|
||||
|
||||
$uploadField->getValidator()->setAllowedExtensions(array_filter(array_merge(Config::inst()->get('File', 'allowed_extensions'), self::$allowed_extensions)));
|
||||
$uploadField->getValidator()->setAllowedExtensions($this->getAllowedExtensions());
|
||||
$exts = $uploadField->getValidator()->getAllowedExtensions();
|
||||
|
||||
asort($exts);
|
||||
$backlink = $this->Backlink();
|
||||
$done = "
|
||||
<a class=\"ss-ui-button ss-ui-action-constructive cms-panel-link ui-corner-all\" href=\"".$backlink."\">
|
||||
Done!
|
||||
<a class=\"ss-ui-button ss-ui-action-constructive cms-panel-link ui-corner-all\" href=\"" . $backlink . "\">
|
||||
" . _t('UploadField.DONE', 'DONE') . "
|
||||
</a>";
|
||||
|
||||
$addExistingField = new DMSDocumentAddExistingField('AddExisting', 'Add Existing');
|
||||
$addExistingField->setRecord($page);
|
||||
$addExistingField = new DMSDocumentAddExistingField(
|
||||
'AddExisting',
|
||||
_t('DMSDocumentAddExistingField.ADDEXISTING', 'Add Existing')
|
||||
);
|
||||
$addExistingField->setRecord($documentSet);
|
||||
|
||||
$form = new Form(
|
||||
$this,
|
||||
'getEditForm',
|
||||
new FieldList(
|
||||
new TabSet('Main',
|
||||
new Tab('From your computer',
|
||||
new HiddenField('ID', false, $page->ID),
|
||||
new TabSet(
|
||||
_t('DMSDocumentAddController.MAINTAB', 'Main'),
|
||||
new Tab(
|
||||
_t('UploadField.FROMCOMPUTER', 'From your computer'),
|
||||
$uploadField,
|
||||
new LiteralField(
|
||||
'AllowedExtensions',
|
||||
|
@ -118,7 +125,8 @@ class DMSDocumentAddController extends LeftAndMain
|
|||
)
|
||||
)
|
||||
),
|
||||
new Tab('From the CMS',
|
||||
new Tab(
|
||||
_t('UploadField.FROMCMS', 'From the CMS'),
|
||||
$addExistingField
|
||||
)
|
||||
)
|
||||
|
@ -131,17 +139,8 @@ class DMSDocumentAddController extends LeftAndMain
|
|||
$form->Backlink = $backlink;
|
||||
// Don't use AssetAdmin_EditForm, as it assumes a different panel structure
|
||||
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
|
||||
/*$form->Fields()->push(
|
||||
new LiteralField(
|
||||
'BackLink',
|
||||
sprintf(
|
||||
'<a href="%s" class="backlink ss-ui-button cms-panel-link" data-icon="back">%s</a>',
|
||||
Controller::join_links(singleton('AssetAdmin')->Link('show'), $folder ? $folder->ID : 0),
|
||||
_t('AssetAdmin.BackToFolder', 'Back to folder')
|
||||
)
|
||||
)
|
||||
);*/
|
||||
//$form->loadDataFrom($folder);
|
||||
$form->Fields()->push(HiddenField::create('ID', false, $documentSet->ID));
|
||||
$form->Fields()->push(HiddenField::create('DSID', false, $documentSet->ID));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
@ -165,27 +164,69 @@ class DMSDocumentAddController extends LeftAndMain
|
|||
}
|
||||
|
||||
$items->push(new ArrayData(array(
|
||||
'Title' => 'Add Document',
|
||||
'Title' => _t('DMSDocumentSet.ADDDOCUMENTBUTTON', 'Add Document'),
|
||||
'Link' => $this->Link()
|
||||
)));
|
||||
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the link to be used to return the user after uploading a document. Scenarios:
|
||||
*
|
||||
* 1) Page context: page ID and document set ID provided, redirect back to the page and document set
|
||||
* 2) Document set context: no page ID, document set ID provided, redirect back to document set in ModelAdmin
|
||||
* 3) Document context: no page ID and no document set ID provided, redirect back to documents in ModelAdmin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Backlink()
|
||||
{
|
||||
$pageID = $this->currentPageID();
|
||||
return Controller::join_links(singleton('CMSPagesController')->Link(), 'edit/show', $pageID);
|
||||
if (!$this->getRequest()->getVar('dsid') || !$this->currentPageID()) {
|
||||
$modelAdmin = new DMSDocumentAdmin;
|
||||
$modelAdmin->init();
|
||||
|
||||
if ($this->getRequest()->getVar('dsid')) {
|
||||
return Controller::join_links(
|
||||
$modelAdmin->Link('DMSDocumentSet'),
|
||||
'EditForm/field/DMSDocumentSet/item',
|
||||
(int) $this->getRequest()->getVar('dsid'),
|
||||
'edit'
|
||||
);
|
||||
}
|
||||
return $modelAdmin->Link();
|
||||
}
|
||||
|
||||
return $this->getPageEditLink($this->currentPageID(), (int) $this->getRequest()->getVar('dsid'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a link to edit a page, deep linking into the document set given
|
||||
*
|
||||
* @param int $pageId
|
||||
* @param int $documentSetId
|
||||
* @return string
|
||||
*/
|
||||
protected function getPageEditLink($pageId, $documentSetId)
|
||||
{
|
||||
return Controller::join_links(
|
||||
CMSPageEditController::singleton()->getEditForm($pageId)->FormAction(),
|
||||
'field/DocumentSets/item',
|
||||
(int) $documentSetId
|
||||
);
|
||||
}
|
||||
|
||||
public function documentautocomplete()
|
||||
{
|
||||
$term = (isset($_GET['term'])) ? $_GET['term'] : '';
|
||||
$term_sql = Convert::raw2sql($term);
|
||||
$term = (string) $this->getRequest()->getVar('term');
|
||||
$termSql = Convert::raw2sql($term);
|
||||
$data = DMSDocument::get()
|
||||
->where("(\"ID\" LIKE '%".$term_sql."%' OR \"Filename\" LIKE '%".$term_sql."%' OR \"Title\" LIKE '%".$term_sql."%')")
|
||||
->sort('ID ASC')
|
||||
->limit(20);
|
||||
->where(
|
||||
'("ID" LIKE \'%' . $termSql . '%\' OR "Filename" LIKE \'%' . $termSql . '%\''
|
||||
. ' OR "Title" LIKE \'%' . $termSql . '%\')'
|
||||
)
|
||||
->sort('ID ASC')
|
||||
->limit(20);
|
||||
|
||||
$return = array();
|
||||
foreach ($data as $doc) {
|
||||
|
@ -195,49 +236,60 @@ class DMSDocumentAddController extends LeftAndMain
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
return json_encode($return);
|
||||
return Convert::raw2json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Link an existing document to the given document set ID
|
||||
* @return string JSON
|
||||
*/
|
||||
public function linkdocument()
|
||||
{
|
||||
$return = array('error' => _t('UploadField.FIELDNOTSET', 'Could not add document to page'));
|
||||
$documentSet = $this->getCurrentDocumentSet();
|
||||
if (!empty($documentSet)) {
|
||||
$document = DMSDocument::get()->byId($this->getRequest()->getVar('documentID'));
|
||||
$documentSet->Documents()->add($document);
|
||||
|
||||
$page = $this->currentPage();
|
||||
if (!empty($page)) {
|
||||
$document = DataObject::get_by_id('DMSDocument', (int) $_GET['documentID']);
|
||||
$document->addPage($page);
|
||||
|
||||
$buttonText = '<button class="ss-uploadfield-item-edit ss-ui-button ui-corner-all" title="Edit this document" data-icon="pencil">'.
|
||||
'Edit<span class="toggle-details"><span class="toggle-details-icon"></span></span></button>';
|
||||
$buttonText = '<button class="ss-uploadfield-item-edit ss-ui-button ui-corner-all"'
|
||||
. ' title="' . _t('DMSDocument.EDITDOCUMENT', 'Edit this document') . '" data-icon="pencil">'
|
||||
. _t('DMSDocument.EDIT', 'Edit') . '<span class="toggle-details">'
|
||||
. '<span class="toggle-details-icon"></span></span></button>';
|
||||
|
||||
// Collect all output data.
|
||||
$return = array(
|
||||
'id' => $document->ID,
|
||||
'name' => $document->getTitle(),
|
||||
'thumbnail_url' => $document->Icon($document->getExtension()),
|
||||
'edit_url' => $this->getEditForm()->Fields()->fieldByName('Main.From your computer.AssetUploadField')->getItemHandler($document->ID)->EditLink(),
|
||||
'edit_url' => $this->getEditForm()->Fields()->fieldByName('Main.From your computer.AssetUploadField')
|
||||
->getItemHandler($document->ID)->EditLink(),
|
||||
'size' => $document->getFileSizeFormatted(),
|
||||
'buttons' => $buttonText,
|
||||
'showeditform' => true
|
||||
);
|
||||
}
|
||||
|
||||
return json_encode($return);
|
||||
return Convert::raw2json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML representing a list of documents that are associated with the given page ID, across all document
|
||||
* sets.
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
public function documentlist()
|
||||
{
|
||||
if (!isset($_GET['pageID'])) {
|
||||
if (!$this->getRequest()->getVar('pageID')) {
|
||||
return $this->httpError(400);
|
||||
}
|
||||
|
||||
$page = SiteTree::get()->byId($_GET['pageID']);
|
||||
$page = SiteTree::get()->byId($this->getRequest()->getVar('pageID'));
|
||||
|
||||
if ($page && $page->Documents()->count() > 0) {
|
||||
if ($page && $page->getAllDocuments()->count() > 0) {
|
||||
$list = '<ul>';
|
||||
|
||||
foreach ($page->Documents() as $document) {
|
||||
foreach ($page->getAllDocuments() as $document) {
|
||||
$list .= sprintf(
|
||||
'<li><a class="add-document" data-document-id="%s">%s</a></li>',
|
||||
$document->ID,
|
||||
|
@ -249,9 +301,51 @@ class DMSDocumentAddController extends LeftAndMain
|
|||
|
||||
return $list;
|
||||
}
|
||||
|
||||
return sprintf('<p>%s</p>',
|
||||
|
||||
return sprintf(
|
||||
'<p>%s</p>',
|
||||
_t('DMSDocumentAddController.NODOCUMENTS', 'There are no documents attached to the selected page.')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of allowed file upload extensions, merged with {@link File} and extra configuration from this
|
||||
* class
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllowedExtensions()
|
||||
{
|
||||
return array_filter(
|
||||
array_merge(
|
||||
(array) Config::inst()->get('File', 'allowed_extensions'),
|
||||
(array) $this->config()->get('allowed_extensions')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the parent method to allow users with access to DMS admin to access this controller
|
||||
*
|
||||
* @param Member $member
|
||||
* @return bool
|
||||
*/
|
||||
public function canView($member = null)
|
||||
{
|
||||
if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
|
||||
$member = Member::currentUser();
|
||||
}
|
||||
|
||||
if ($member &&
|
||||
Permission::checkMember(
|
||||
$member,
|
||||
array(
|
||||
'CMS_ACCESS_DMSDocumentAdmin',
|
||||
)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return parent::canView($member);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
class DMSDocumentAddExistingField extends CompositeField
|
||||
{
|
||||
|
||||
public $useFieldContext = true;
|
||||
|
||||
public function __construct($name, $title = null)
|
||||
|
@ -10,7 +9,15 @@ class DMSDocumentAddExistingField extends CompositeField
|
|||
$this->name = $name;
|
||||
$this->title = ($title === null) ? $name : $title;
|
||||
|
||||
parent::__construct(new TreeDropdownField('PageSelector', 'Add from another page', 'SiteTree', 'ID', 'TitleWithNumberOfDocuments'));
|
||||
parent::__construct(
|
||||
new TreeDropdownField(
|
||||
'PageSelector',
|
||||
'Add from another page',
|
||||
'SiteTree',
|
||||
'ID',
|
||||
'TitleWithNumberOfDocuments'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,7 +30,8 @@ class DMSDocumentAddExistingField extends CompositeField
|
|||
return $this;
|
||||
}
|
||||
/**
|
||||
* Get the record to use as "Parent" for uploaded Files (eg a Page with a has_one to File) If none is set, it will use Form->getRecord() or Form->Controller()->data()
|
||||
* Get the record to use as "Parent" for uploaded Files (eg a Page with a has_one to File) If none is set, it
|
||||
* will use Form->getRecord() or Form->Controller()->data()
|
||||
* @return DataObject
|
||||
*/
|
||||
public function getRecord()
|
||||
|
@ -46,8 +54,9 @@ class DMSDocumentAddExistingField extends CompositeField
|
|||
|
||||
public function Field($properties = array())
|
||||
{
|
||||
Requirements::javascript(DMS_DIR.'/javascript/DMSDocumentAddExistingField.js');
|
||||
Requirements::javascript(DMS_DIR."/javascript/DocumentHtmlEditorFieldToolbar.js");
|
||||
Requirements::javascript(DMS_DIR . '/javascript/DMSDocumentAddExistingField.js');
|
||||
Requirements::javascript(DMS_DIR . '/javascript/DocumentHtmlEditorFieldToolbar.js');
|
||||
Requirements::css(DMS_DIR . '/dist/css/cmsbundle.css');
|
||||
|
||||
return $this->renderWith('DMSDocumentAddExistingField');
|
||||
}
|
||||
|
@ -55,9 +64,12 @@ class DMSDocumentAddExistingField extends CompositeField
|
|||
/**
|
||||
* Sets or unsets the use of the "field" class in the template. The "field" class adds Javascript behaviour
|
||||
* that causes unwelcome hiding side-effects when this Field is used within the link editor pop-up
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUseFieldClass($use = false)
|
||||
{
|
||||
$this->useFieldContext = $use;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
class DMSDocumentAdmin extends ModelAdmin
|
||||
{
|
||||
private static $managed_models = array(
|
||||
'DMSDocument',
|
||||
'DMSDocumentSet'
|
||||
);
|
||||
|
||||
private static $url_segment = 'documents';
|
||||
|
||||
private static $menu_title = 'Documents';
|
||||
|
||||
private static $menu_icon = 'dms/images/app_icons/drawer.png';
|
||||
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
Requirements::javascript(DMS_DIR . '/javascript/DMSGridField.js');
|
||||
}
|
||||
/**
|
||||
* Remove the default "add" button and replace it with a customised version for DMS
|
||||
*
|
||||
* @return CMSForm
|
||||
*/
|
||||
public function getEditForm($id = null, $fields = null)
|
||||
{
|
||||
/** @var CMSForm $form */
|
||||
$form = parent::getEditForm($id, $fields);
|
||||
$gridField = $form->Fields()->fieldByName($this->sanitiseClassName($this->modelClass));
|
||||
return $this->modifyGridField($form, $gridField);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the GridField is for DMSDocument then add a custom "add" button. If it's for DMSDocumentSet then
|
||||
* update the display fields to include some extra columns that are only for this ModelAdmin, so cannot
|
||||
* be added directly to the model's display fields.
|
||||
*
|
||||
* @param CMSForm $form
|
||||
* @param GridField $gridField
|
||||
* @return CMSForm
|
||||
*/
|
||||
protected function modifyGridField(CMSForm $form, GridField $gridField)
|
||||
{
|
||||
$gridFieldConfig = $gridField->getConfig();
|
||||
|
||||
$gridFieldConfig->removeComponentsByType('GridFieldEditButton');
|
||||
$gridFieldConfig->addComponent(new DMSGridFieldEditButton(), 'GridFieldDeleteAction');
|
||||
|
||||
if ($this->modelClass === 'DMSDocument') {
|
||||
$gridFieldConfig->removeComponentsByType('GridFieldAddNewButton');
|
||||
$gridFieldConfig->addComponent(
|
||||
new DMSGridFieldAddNewButton('buttons-before-left'),
|
||||
'GridFieldExportButton'
|
||||
);
|
||||
} elseif ($this->modelClass === 'DMSDocumentSet') {
|
||||
$dataColumns = $gridFieldConfig->getComponentByType('GridFieldDataColumns');
|
||||
$fields = $dataColumns->getDisplayFields($gridField);
|
||||
$fields = array('Title' => 'Title', 'Page.Title' => 'Page') + $fields;
|
||||
$dataColumns->setDisplayFields($fields)
|
||||
->setFieldFormatting(
|
||||
array(
|
||||
'Page.Title' => function ($value, $item) {
|
||||
// Link a page click directly to the Document Set on the actual page
|
||||
if ($page = SiteTree::get()->byID($item->PageID)) {
|
||||
return sprintf(
|
||||
"<a class='dms-doc-sets-link' href='%s/#Root_DocumentSets%s'>$value</a>",
|
||||
$page->CMSEditLink(),
|
||||
$page->DocumentSets()->count()
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
class DMSGridFieldAddNewButton extends GridFieldAddNewButton implements GridField_HTMLProvider
|
||||
{
|
||||
/**
|
||||
* The document set ID that the document should be attached to
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $documentSetId;
|
||||
|
||||
/**
|
||||
* Overriding the parent method to change the template that the DMS add button will be rendered with
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @return array
|
||||
*/
|
||||
public function getHTMLFragments($gridField)
|
||||
{
|
||||
$singleton = singleton($gridField->getModelClass());
|
||||
|
||||
if (!$singleton->canCreate()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if (!$this->buttonName) {
|
||||
// provide a default button name, can be changed by calling {@link setButtonName()} on this component
|
||||
$objectName = $singleton->i18n_singular_name();
|
||||
$this->buttonName = _t('GridField.Add', 'Add {name}', array('name' => $objectName));
|
||||
}
|
||||
|
||||
$link = singleton('DMSDocumentAddController')->Link();
|
||||
if ($this->getDocumentSetId()) {
|
||||
$link = Controller::join_links($link, '?dsid=' . $this->getDocumentSetId());
|
||||
|
||||
// Look for an associated page, but only share it if we're editing in a page context
|
||||
$set = DMSDocumentSet::get()->byId($this->getDocumentSetId());
|
||||
if ($set && $set->exists() && $set->Page()->exists()
|
||||
&& Controller::curr() instanceof CMSPageEditController
|
||||
) {
|
||||
$link = Controller::join_links($link, '?page_id=' . $set->Page()->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$data = new ArrayData(array(
|
||||
'NewLink' => $link,
|
||||
'ButtonName' => $this->buttonName,
|
||||
));
|
||||
|
||||
return array(
|
||||
$this->targetFragment => $data->renderWith('DMSGridFieldAddNewButton'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the document set ID that this document should be attached to
|
||||
*
|
||||
* @param int $id
|
||||
* @return $this
|
||||
*/
|
||||
public function setDocumentSetId($id)
|
||||
{
|
||||
$this->documentSetId = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the document set ID that this document should be attached to
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDocumentSetId()
|
||||
{
|
||||
return $this->documentSetId;
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* This class is a {@link GridField} component that adds a delete a DMS document.
|
||||
*
|
||||
* This component also supports unlinking a relation instead of deleting the object. By default it unlinks, but if
|
||||
* this is the last reference to a specific document, it warns the user that continuing with the operation will
|
||||
* delete the document completely.
|
||||
*
|
||||
* <code>
|
||||
* $action = new GridFieldDeleteAction(); // delete objects permanently
|
||||
* </code>
|
||||
*
|
||||
* @package dms
|
||||
* @subpackage cms
|
||||
*/
|
||||
class DMSGridFieldDeleteAction extends GridFieldDeleteAction implements GridField_ColumnProvider, GridField_ActionProvider
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
* @return string - the HTML for the column
|
||||
*/
|
||||
public function getColumnContent($gridField, $record, $columnName)
|
||||
{
|
||||
if ($this->removeRelation) {
|
||||
$field = GridField_FormAction::create($gridField, 'UnlinkRelation'.$record->ID, false, "unlinkrelation", array('RecordID' => $record->ID))
|
||||
->addExtraClass('gridfield-button-unlink')
|
||||
->setAttribute('title', _t('GridAction.UnlinkRelation', "Unlink"))
|
||||
->setAttribute('data-icon', 'chain--minus');
|
||||
} else {
|
||||
if (!$record->canDelete()) {
|
||||
return;
|
||||
}
|
||||
$field = GridField_FormAction::create($gridField, 'DeleteRecord'.$record->ID, false, "deleterecord", array('RecordID' => $record->ID))
|
||||
->addExtraClass('gridfield-button-delete')
|
||||
->setAttribute('title', _t('GridAction.Delete', "Delete"))
|
||||
->setAttribute('data-icon', 'cross-circle')
|
||||
->setDescription(_t('GridAction.DELETE_DESCRIPTION', 'Delete'));
|
||||
}
|
||||
|
||||
//add a class to the field to if it is the last gridfield in the list
|
||||
$numberOfRelations = $record->Pages()->Count();
|
||||
$field->addExtraClass('dms-delete') //add a new class for custom JS to handle the delete action
|
||||
->setAttribute('data-pages-count', $numberOfRelations) //add the number of pages attached to this field as a data-attribute
|
||||
->removeExtraClass('gridfield-button-delete'); //remove the base gridfield behaviour
|
||||
|
||||
//set a class telling JS what kind of warning to display when clicking the delete button
|
||||
if ($numberOfRelations > 1) {
|
||||
$field->addExtraClass('dms-delete-link-only');
|
||||
} else {
|
||||
$field->addExtraClass('dms-delete-last-warning');
|
||||
}
|
||||
|
||||
//set a class to show if the document is hidden
|
||||
if ($record->isHidden()) {
|
||||
$field->addExtraClass('dms-document-hidden');
|
||||
}
|
||||
|
||||
return $field->Field();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the actions and apply any changes to the GridField
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param string $actionName
|
||||
* @param mixed $arguments
|
||||
* @param array $data - form data
|
||||
* @return void
|
||||
*/
|
||||
public function handleAction(GridField $gridField, $actionName, $arguments, $data)
|
||||
{
|
||||
if ($actionName == 'deleterecord' || $actionName == 'unlinkrelation') {
|
||||
$item = $gridField->getList()->byID($arguments['RecordID']);
|
||||
if (!$item) {
|
||||
return;
|
||||
}
|
||||
if ($actionName == 'deleterecord' && !$item->canDelete()) {
|
||||
throw new ValidationException(_t('GridFieldAction_Delete.DeletePermissionsFailure', "No delete permissions"), 0);
|
||||
}
|
||||
|
||||
$delete = false;
|
||||
if ($item->Pages()->Count() <= 1) {
|
||||
$delete = true;
|
||||
}
|
||||
|
||||
$gridField->getList()->remove($item); //remove the relation
|
||||
if ($delete) {
|
||||
$item->delete();
|
||||
} //delete the DMSDocument
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ class DMSGridFieldDetailForm_ItemRequest extends GridFieldDetailForm_ItemRequest
|
|||
|
||||
//add a data attribute specifying how many pages this document is referenced on
|
||||
if ($record = $this->record) {
|
||||
$numberOfPageRelations = $record->Pages()->Count();
|
||||
$numberOfPageRelations = $record->getRelatedPages()->count();
|
||||
$relations = new ShortCodeRelationFinder();
|
||||
$numberOfInlineRelations = $relations->findPageCount($record->ID);
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
class DMSGridFieldEditButton extends GridFieldEditButton implements GridField_ColumnProvider
|
||||
{
|
||||
|
||||
/**
|
||||
* Overriding the parent method to change the template that the DMS edit button will be rendered with based on
|
||||
* whether or not the user has edit permissions.
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
*
|
||||
* @return string - the HTML for the column
|
||||
*/
|
||||
public function getColumnContent($gridField, $record, $columnName)
|
||||
{
|
||||
$data = new ArrayData(array(
|
||||
'Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit')
|
||||
));
|
||||
|
||||
$template = $record->canEdit() ? 'GridFieldEditButton' : 'GridFieldViewButton';
|
||||
|
||||
return $data->renderWith($template);
|
||||
}
|
||||
}
|
|
@ -18,17 +18,12 @@ class DMSUploadField extends UploadField
|
|||
"upload",
|
||||
);
|
||||
|
||||
/**
|
||||
* The temporary folder name to store files in during upload
|
||||
* @var string
|
||||
*/
|
||||
protected $folderName = 'DMSTemporaryUploads';
|
||||
|
||||
public function __construct($name, $title = null, SS_List $items = null)
|
||||
{
|
||||
parent::__construct($name, $title, $items);
|
||||
|
||||
//set default DMS replace template to false
|
||||
$this->setConfig('useDMSReplaceTemplate', 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override the default behaviour of the UploadField and take the uploaded file (uploaded to assets) and
|
||||
* add it into the DMS storage, deleting the old/uploaded file.
|
||||
|
@ -48,9 +43,12 @@ class DMSUploadField extends UploadField
|
|||
// Otherwise create it
|
||||
$doc = $dms->storeDocument($file);
|
||||
$file->delete();
|
||||
// Relate to the underlying page being edited.
|
||||
// Not applicable when editing the document itself and replacing it.
|
||||
$doc->addPage($record);
|
||||
}
|
||||
|
||||
// Relate to the underlying document set being edited.
|
||||
// Not applicable when editing the document itself and replacing it, or uploading from the ModelAdmin
|
||||
if ($record instanceof DMSDocumentSet) {
|
||||
$record->Documents()->add($doc, array('ManuallyAdded' => 1));
|
||||
}
|
||||
|
||||
return $doc;
|
||||
|
@ -61,25 +59,18 @@ class DMSUploadField extends UploadField
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function isDisabled()
|
||||
{
|
||||
return (parent::isDisabled() || !$this->isSaveable());
|
||||
}
|
||||
|
||||
public function isSaveable()
|
||||
{
|
||||
return (!empty($this->getRecord()->ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to handle upload of a single file
|
||||
*
|
||||
*
|
||||
* @param SS_HTTPRequest $request
|
||||
* @return string json
|
||||
*/
|
||||
public function upload(SS_HTTPRequest $request)
|
||||
{
|
||||
if ($recordId = $request->postVar('ID')) {
|
||||
$this->setRecord(DMSDocumentSet::get()->byId($recordId));
|
||||
}
|
||||
|
||||
if ($this->isDisabled() || $this->isReadonly()) {
|
||||
return $this->httpError(403);
|
||||
}
|
||||
|
@ -93,7 +84,7 @@ class DMSUploadField extends UploadField
|
|||
$name = $this->getName();
|
||||
$tmpfile = $request->postVar($name);
|
||||
$record = $this->getRecord();
|
||||
|
||||
|
||||
// Check if the file has been uploaded into the temporary storage.
|
||||
if (!$tmpfile) {
|
||||
$return = array('error' => _t('UploadField.FIELDNOTSET', 'File information not found'));
|
||||
|
@ -110,13 +101,13 @@ class DMSUploadField extends UploadField
|
|||
if (!$return['error'] && $this->relationAutoSetting && $record && $record->exists()) {
|
||||
$tooManyFiles = false;
|
||||
// Some relationships allow many files to be attached.
|
||||
if ($this->getConfig('allowedMaxFileNumber') && ($record->has_many($name) || $record->many_many($name))) {
|
||||
if ($this->getConfig('allowedMaxFileNumber') && ($record->hasMany($name) || $record->manyMany($name))) {
|
||||
if (!$record->isInDB()) {
|
||||
$record->write();
|
||||
}
|
||||
$tooManyFiles = $record->{$name}()->count() >= $this->getConfig('allowedMaxFileNumber');
|
||||
// has_one only allows one file at any given time.
|
||||
} elseif ($record->has_one($name)) {
|
||||
} elseif ($record->hasOne($name)) {
|
||||
$tooManyFiles = $record->{$name}() && $record->{$name}()->exists();
|
||||
}
|
||||
|
||||
|
@ -141,13 +132,13 @@ class DMSUploadField extends UploadField
|
|||
// Search for relations that can hold the uploaded files.
|
||||
if ($relationClass = $this->getRelationAutosetClass()) {
|
||||
// Create new object explicitly. Otherwise rely on Upload::load to choose the class.
|
||||
$fileObject = Object::create($relationClass);
|
||||
$fileObject = SS_Object::create($relationClass);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the uploaded file into a new file object.
|
||||
try {
|
||||
$this->upload->loadIntoFile($tmpfile, $fileObject, $this->folderName);
|
||||
$this->upload->loadIntoFile($tmpfile, $fileObject, $this->getFolderName());
|
||||
} catch (Exception $e) {
|
||||
// we shouldn't get an error here, but just in case
|
||||
$return['error'] = $e->getMessage();
|
||||
|
@ -155,13 +146,13 @@ class DMSUploadField extends UploadField
|
|||
|
||||
if (!$return['error']) {
|
||||
if ($this->upload->isError()) {
|
||||
$return['error'] = implode(' '.PHP_EOL, $this->upload->getErrors());
|
||||
$return['error'] = implode(' ' . PHP_EOL, $this->upload->getErrors());
|
||||
} else {
|
||||
$file = $this->upload->getFile();
|
||||
|
||||
// CUSTOM Attach the file to the related record.
|
||||
$document = $this->attachFile($file);
|
||||
|
||||
|
||||
// Collect all output data.
|
||||
$return = array_merge($return, array(
|
||||
'id' => $document->ID,
|
||||
|
@ -198,10 +189,10 @@ class DMSUploadField extends UploadField
|
|||
|
||||
// Replace the download template with a new one only when access the upload field through a GridField.
|
||||
// Needs to be enabled through setConfig('downloadTemplateName', 'ss-dmsuploadfield-downloadtemplate');
|
||||
Requirements::javascript('dms/javascript/DMSUploadField_downloadtemplate.js');
|
||||
|
||||
Requirements::javascript(DMS_DIR . '/javascript/DMSUploadField_downloadtemplate.js');
|
||||
|
||||
// In the add dialog, add the addtemplate into the set of file that load.
|
||||
Requirements::javascript('dms/javascript/DMSUploadField_addtemplate.js');
|
||||
Requirements::javascript(DMS_DIR . '/javascript/DMSUploadField_addtemplate.js');
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
@ -214,7 +205,7 @@ class DMSUploadField extends UploadField
|
|||
{
|
||||
return DMSUploadField_ItemHandler::create($this, $itemID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* FieldList $fields for the EditForm
|
||||
|
@ -223,24 +214,26 @@ class DMSUploadField extends UploadField
|
|||
* @param File $file File context to generate fields for
|
||||
* @return FieldList List of form fields
|
||||
*/
|
||||
public function getDMSFileEditFields($file)
|
||||
{
|
||||
public function getDMSFileEditFields($file)
|
||||
{
|
||||
|
||||
// Empty actions, generate default
|
||||
if(empty($this->fileEditFields)) {
|
||||
if (empty($this->fileEditFields)) {
|
||||
$fields = $file->getCMSFields();
|
||||
// Only display main tab, to avoid overly complex interface
|
||||
if($fields->hasTabSet() && ($mainTab = $fields->findOrMakeTab('Root.Main'))) {
|
||||
if ($fields->hasTabSet() && ($mainTab = $fields->findOrMakeTab('Root.Main'))) {
|
||||
$fields = $mainTab->Fields();
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
// Fields instance
|
||||
if ($this->fileEditFields instanceof FieldList) return $this->fileEditFields;
|
||||
if ($this->fileEditFields instanceof FieldList) {
|
||||
return $this->fileEditFields;
|
||||
}
|
||||
|
||||
// Method to call on the given file
|
||||
if($file->hasMethod($this->fileEditFields)) {
|
||||
if ($file->hasMethod($this->fileEditFields)) {
|
||||
return $file->{$this->fileEditFields}();
|
||||
}
|
||||
|
||||
|
@ -254,21 +247,23 @@ class DMSUploadField extends UploadField
|
|||
* @param File $file File context to generate form actions for
|
||||
* @return FieldList Field list containing FormAction
|
||||
*/
|
||||
public function getDMSFileEditActions($file)
|
||||
{
|
||||
public function getDMSFileEditActions($file)
|
||||
{
|
||||
|
||||
// Empty actions, generate default
|
||||
if(empty($this->fileEditActions)) {
|
||||
if (empty($this->fileEditActions)) {
|
||||
$actions = new FieldList($saveAction = new FormAction('doEdit', _t('UploadField.DOEDIT', 'Save')));
|
||||
$saveAction->addExtraClass('ss-ui-action-constructive icon-accept');
|
||||
return $actions;
|
||||
}
|
||||
|
||||
// Actions instance
|
||||
if ($this->fileEditActions instanceof FieldList) return $this->fileEditActions;
|
||||
if ($this->fileEditActions instanceof FieldList) {
|
||||
return $this->fileEditActions;
|
||||
}
|
||||
|
||||
// Method to call on the given file
|
||||
if($file->hasMethod($this->fileEditActions)) {
|
||||
if ($file->hasMethod($this->fileEditActions)) {
|
||||
return $file->{$this->fileEditActions}();
|
||||
}
|
||||
|
||||
|
@ -282,58 +277,45 @@ class DMSUploadField extends UploadField
|
|||
* @param File $file File context to generate validator from
|
||||
* @return Validator Validator object
|
||||
*/
|
||||
public function getDMSFileEditValidator($file)
|
||||
{
|
||||
public function getDMSFileEditValidator($file)
|
||||
{
|
||||
// Empty validator
|
||||
if(empty($this->fileEditValidator)) return null;
|
||||
if (empty($this->fileEditValidator)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Validator instance
|
||||
if($this->fileEditValidator instanceof Validator) return $this->fileEditValidator;
|
||||
if ($this->fileEditValidator instanceof Validator) {
|
||||
return $this->fileEditValidator;
|
||||
}
|
||||
|
||||
// Method to call on the given file
|
||||
if($file->hasMethod($this->fileEditValidator)) {
|
||||
if ($file->hasMethod($this->fileEditValidator)) {
|
||||
return $file->{$this->fileEditValidator}();
|
||||
}
|
||||
|
||||
user_error("Invalid value for UploadField::fileEditValidator", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
class DMSUploadField_ItemHandler extends UploadField_ItemHandler
|
||||
{
|
||||
|
||||
private static $allowed_actions = array(
|
||||
'delete',
|
||||
'edit',
|
||||
'EditForm',
|
||||
);
|
||||
|
||||
public function getItem()
|
||||
{
|
||||
return DataObject::get_by_id('DMSDocument', $this->itemID);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Form
|
||||
* Set the folder name to store DMS files in
|
||||
*
|
||||
* @param string $folderName
|
||||
* @return $this
|
||||
*/
|
||||
public function EditForm() {
|
||||
$file = $this->getItem();
|
||||
|
||||
// Get form components
|
||||
$fields = $this->parent->getDMSFileEditFields($file);
|
||||
$actions = $this->parent->getDMSFileEditActions($file);
|
||||
$validator = $this->parent->getDMSFileEditValidator($file);
|
||||
$form = new Form(
|
||||
$this,
|
||||
__FUNCTION__,
|
||||
$fields,
|
||||
$actions,
|
||||
$validator
|
||||
);
|
||||
$form->loadDataFrom($file);
|
||||
$form->addExtraClass('small');
|
||||
|
||||
return $form;
|
||||
public function setFolderName($folderName)
|
||||
{
|
||||
$this->folderName = (string) $folderName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder name for storing the document
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFolderName()
|
||||
{
|
||||
return $this->folderName;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
class DMSUploadField_ItemHandler extends UploadField_ItemHandler
|
||||
{
|
||||
private static $allowed_actions = array(
|
||||
'delete',
|
||||
'edit',
|
||||
'EditForm',
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets a DMS document by its ID
|
||||
*
|
||||
* @return DMSDocument
|
||||
*/
|
||||
public function getItem()
|
||||
{
|
||||
return DMSDocument::get()->byId($this->itemID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Form
|
||||
*/
|
||||
public function EditForm()
|
||||
{
|
||||
$file = $this->getItem();
|
||||
|
||||
// Get form components
|
||||
$fields = $this->parent->getDMSFileEditFields($file);
|
||||
$actions = $this->parent->getDMSFileEditActions($file);
|
||||
$validator = $this->parent->getDMSFileEditValidator($file);
|
||||
$form = new Form(
|
||||
$this,
|
||||
__FUNCTION__,
|
||||
$fields,
|
||||
$actions,
|
||||
$validator
|
||||
);
|
||||
$form->loadDataFrom($file);
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
|
@ -2,11 +2,8 @@
|
|||
/**
|
||||
* Extends the original toolbar with document picking capability - modified lines are commented.
|
||||
*/
|
||||
|
||||
|
||||
class DocumentHtmlEditorFieldToolbar extends Extension
|
||||
{
|
||||
|
||||
public function updateLinkForm(Form $form)
|
||||
{
|
||||
$linkType = null;
|
||||
|
@ -29,6 +26,8 @@ class DocumentHtmlEditorFieldToolbar extends Extension
|
|||
$addExistingField->setUseFieldClass(false);
|
||||
$fieldList->insertAfter($addExistingField, 'Description');
|
||||
|
||||
$fieldList->push(HiddenField::create('DMSShortcodeHandlerKey', false, DMS::inst()->getShortcodeHandlerKey()));
|
||||
|
||||
// Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/behaviour/behaviour.js");
|
||||
// Requirements::javascript(SAPPHIRE_DIR . "/javascript/tiny_mce_improvements.js");
|
||||
//
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
class DMSDocumentTaxonomyExtension extends DataExtension
|
||||
{
|
||||
private static $many_many = array(
|
||||
'Tags' => 'TaxonomyTerm'
|
||||
);
|
||||
|
||||
/**
|
||||
* Push an autocomplete dropdown for the available tags in documents
|
||||
*
|
||||
* @param FieldList $fields
|
||||
*/
|
||||
public function updateCMSFields(FieldList $fields)
|
||||
{
|
||||
$tags = $this->getAllTagsMap();
|
||||
$tagField = ListboxField::create('Tags', _t('DMSDocumentTaxonomyExtension.TAGS', 'Tags'))
|
||||
->setMultiple(true)
|
||||
->setSource($tags);
|
||||
|
||||
if (empty($tags)) {
|
||||
$tagField->setAttribute('data-placeholder', _t('DMSDocumentTaxonomyExtension.NOTAGS', 'No tags found'));
|
||||
}
|
||||
|
||||
$fields->insertAfter('Description', $tagField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of all the available tags that a document can use. Will return a list containing a taxonomy
|
||||
* term's entire hierarchy, e.g. "Photo > Attribute > Density > High"
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllTagsMap()
|
||||
{
|
||||
$tags = TaxonomyTerm::get()->filter(
|
||||
'Type.Name:ExactMatch',
|
||||
Config::inst()->get('DMSTaxonomyTypeExtension', 'default_record_name')
|
||||
);
|
||||
|
||||
$map = array();
|
||||
foreach ($tags as $tag) {
|
||||
$nameParts = array($tag->Name);
|
||||
$currentTag = $tag;
|
||||
|
||||
while ($currentTag->Parent() && $currentTag->Parent()->exists()) {
|
||||
array_unshift($nameParts, $currentTag->Parent()->Name);
|
||||
$currentTag = $currentTag->Parent();
|
||||
}
|
||||
|
||||
$map[$tag->ID] = implode(' > ', $nameParts);
|
||||
}
|
||||
return $map;
|
||||
}
|
||||
}
|
|
@ -5,137 +5,79 @@
|
|||
*/
|
||||
class DMSSiteTreeExtension extends DataExtension
|
||||
{
|
||||
|
||||
private static $belongs_many_many = array(
|
||||
'Documents' => 'DMSDocument'
|
||||
private static $has_many = array(
|
||||
'DocumentSets' => 'DMSDocumentSet'
|
||||
);
|
||||
|
||||
private static $noDocumentsList = array();
|
||||
|
||||
private static $showDocumentsList = array();
|
||||
|
||||
/**
|
||||
* Do not show the documents tab on the array of pages set here
|
||||
* @static
|
||||
* @param $mixed Array of page types to not show the Documents tab on
|
||||
*/
|
||||
public static function no_documents_tab($array = array())
|
||||
{
|
||||
if (empty($array)) {
|
||||
return;
|
||||
}
|
||||
if (is_array($array)) {
|
||||
self::$noDocumentsList = $array;
|
||||
} else {
|
||||
self::$noDocumentsList = array($array);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only show the documents tab on the list of pages set here. Any pages set in the no_documents_tab array will
|
||||
* still not be shown. If this isn't called, or if it is called with an empty array, all pages will get Document tabs.
|
||||
* @static
|
||||
* @param $array Array of page types to show the Documents tab on
|
||||
*/
|
||||
public static function show_documents_tab($array = array())
|
||||
{
|
||||
if (empty($array)) {
|
||||
return;
|
||||
}
|
||||
if (is_array($array)) {
|
||||
self::$showDocumentsList = $array;
|
||||
} else {
|
||||
self::$showDocumentsList = array($array);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateCMSFields(FieldList $fields)
|
||||
{
|
||||
//prevent certain pages from having a Document tab in the CMS
|
||||
if (in_array($this->owner->ClassName, self::$noDocumentsList)) {
|
||||
return;
|
||||
}
|
||||
if (count(self::$showDocumentsList) > 0 && !in_array($this->owner->ClassName, self::$showDocumentsList)) {
|
||||
// Ability to disable document sets for a Page
|
||||
if (!$this->owner->config()->get('documents_enabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
//javascript to customize the grid field for the DMS document (overriding entwine in FRAMEWORK_DIR.'/javascript/GridField.js'
|
||||
Requirements::javascript(DMS_DIR.'/javascript/DMSGridField.js');
|
||||
Requirements::css(DMS_DIR.'/css/DMSMainCMS.css');
|
||||
|
||||
//javascript for the link editor pop-up in TinyMCE
|
||||
Requirements::javascript(DMS_DIR."/javascript/DocumentHtmlEditorFieldToolbar.js");
|
||||
|
||||
// Document listing
|
||||
$gridFieldConfig = GridFieldConfig::create()->addComponents(
|
||||
new GridFieldToolbarHeader(),
|
||||
new GridFieldFilterHeader(),
|
||||
new GridFieldSortableHeader(),
|
||||
new GridFieldOrderableRows('DocumentSort'),
|
||||
new GridFieldDataColumns(),
|
||||
new GridFieldEditButton(),
|
||||
new DMSGridFieldDeleteAction(), //special delete dialog to handle custom behaviour of unlinking and deleting
|
||||
new GridFieldDetailForm()
|
||||
//GridFieldLevelup::create($folder->ID)->setLinkSpec('admin/assets/show/%d')
|
||||
);
|
||||
|
||||
if (class_exists('GridFieldPaginatorWithShowAll')) {
|
||||
$paginatorComponent = new GridFieldPaginatorWithShowAll(15);
|
||||
} else {
|
||||
$paginatorComponent = new GridFieldPaginator(15);
|
||||
// Hides the DocumentSets tab if the user has no permisions
|
||||
if (!Permission::checkMember(
|
||||
Member::currentUser(),
|
||||
array('ADMIN', 'CMS_ACCESS_DMSDocumentAdmin')
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
$gridFieldConfig->addComponent($paginatorComponent);
|
||||
|
||||
if (class_exists('GridFieldSortableRows')) {
|
||||
$sortableComponent = new GridFieldSortableRows('DocumentSort');
|
||||
//setUsePagenation method removed from newer version of SortableGridField.
|
||||
if (method_exists($sortableComponent, 'setUsePagination')) {
|
||||
$sortableComponent->setUsePagination(false)->setForceRedraw(true);
|
||||
}
|
||||
$gridFieldConfig->addComponent($sortableComponent);
|
||||
}
|
||||
|
||||
// HACK: Create a singleton of DMSDocument to ensure extensions are applied before we try to get display fields.
|
||||
singleton('DMSDocument');
|
||||
$gridFieldConfig->getComponentByType('GridFieldDataColumns')->setDisplayFields(Config::inst()->get('DMSDocument', 'display_fields'))
|
||||
->setFieldCasting(array('LastChanged'=>"Datetime->Ago"))
|
||||
->setFieldFormatting(array('FilenameWithoutID'=>'<a target=\'_blank\' class=\'file-url\' href=\'$Link\'>$FilenameWithoutID</a>'));
|
||||
|
||||
//override delete functionality with this class
|
||||
$gridFieldConfig->getComponentByType('GridFieldDetailForm')->setItemRequestClass('DMSGridFieldDetailForm_ItemRequest');
|
||||
|
||||
$gridField = GridField::create(
|
||||
'Documents',
|
||||
'DocumentSets',
|
||||
false,
|
||||
$this->owner->Documents()->Sort('DocumentSort'),
|
||||
$gridFieldConfig
|
||||
$this->owner->DocumentSets(), //->Sort('DocumentSort'),
|
||||
$config = new GridFieldConfig_RelationEditor
|
||||
);
|
||||
$gridField->addExtraClass('documents');
|
||||
$gridField->addExtraClass('documentsets');
|
||||
|
||||
$uploadBtn = new LiteralField(
|
||||
'UploadButton',
|
||||
sprintf(
|
||||
'<a class="ss-ui-button ss-ui-action-constructive cms-panel-link" data-pjax-target="Content" data-icon="add" href="%s">%s</a>',
|
||||
Controller::join_links(singleton('DMSDocumentAddController')->Link(), '?ID=' . $this->owner->ID),
|
||||
"Add Documents"
|
||||
)
|
||||
// Only show document sets in the autocompleter that have not been assigned to a page already
|
||||
$config->getComponentByType('GridFieldAddExistingAutocompleter')->setSearchList(
|
||||
DMSDocumentSet::get()->filter(array('PageID' => 0))
|
||||
);
|
||||
|
||||
$fields->addFieldsToTab(
|
||||
'Root.Documents (' . $this->owner->Documents()->Count() . ')',
|
||||
array(
|
||||
$uploadBtn,
|
||||
$gridField
|
||||
)
|
||||
$fields->addFieldToTab(
|
||||
'Root.DocumentSets',
|
||||
$gridField
|
||||
);
|
||||
|
||||
$fields
|
||||
->findOrMakeTab('Root.DocumentSets')
|
||||
->setTitle(_t(
|
||||
__CLASS__ . '.DocumentSetsTabTitle',
|
||||
'Document Sets ({count})',
|
||||
array('count' => $this->owner->DocumentSets()->count())
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce sorting for frontend
|
||||
* Get a list of document sets for the owner page
|
||||
*
|
||||
* @return ArrayList
|
||||
*/
|
||||
public function PageDocuments()
|
||||
public function getDocumentSets()
|
||||
{
|
||||
return $this->owner->getManyManyComponents('Documents')->sort('DocumentSort');
|
||||
return $this->owner->DocumentSets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all documents from all document sets for the owner page
|
||||
*
|
||||
* @return ArrayList
|
||||
*/
|
||||
public function getAllDocuments()
|
||||
{
|
||||
$documents = ArrayList::create();
|
||||
|
||||
foreach ($this->getDocumentSets() as $documentSet) {
|
||||
/** @var DocumentSet $documentSet */
|
||||
$documents->merge($documentSet->getDocuments());
|
||||
}
|
||||
$documents->removeDuplicates();
|
||||
|
||||
return $documents;
|
||||
}
|
||||
|
||||
public function onBeforeDelete()
|
||||
|
@ -148,11 +90,11 @@ class DMSSiteTreeExtension extends DataExtension
|
|||
|
||||
// Only remove if record doesn't still exist on live stage.
|
||||
if (!$existsOnOtherStage) {
|
||||
$dmsDocuments = $this->owner->Documents();
|
||||
$dmsDocuments = $this->owner->getAllDocuments();
|
||||
foreach ($dmsDocuments as $document) {
|
||||
//if the document is only associated with one page, i.e. only associated with this page
|
||||
if ($document->Pages()->Count() <= 1) {
|
||||
//delete the document before deleting this page
|
||||
// If the document is only associated with one page, i.e. only associated with this page
|
||||
if ($document->getRelatedPages()->count() <= 1) {
|
||||
// Delete the document before deleting this page
|
||||
$document->delete();
|
||||
}
|
||||
}
|
||||
|
@ -161,8 +103,8 @@ class DMSSiteTreeExtension extends DataExtension
|
|||
|
||||
public function onBeforePublish()
|
||||
{
|
||||
$embargoedDocuments = $this->owner->Documents()->filter('EmbargoedUntilPublished', true);
|
||||
if ($embargoedDocuments->Count() > 0) {
|
||||
$embargoedDocuments = $this->owner->getAllDocuments()->filter('EmbargoedUntilPublished', true);
|
||||
if ($embargoedDocuments->count() > 0) {
|
||||
foreach ($embargoedDocuments as $doc) {
|
||||
$doc->EmbargoedUntilPublished = false;
|
||||
$doc->write();
|
||||
|
@ -170,8 +112,14 @@ class DMSSiteTreeExtension extends DataExtension
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title of the page with the total number of documents it has associated with it across
|
||||
* all document sets
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitleWithNumberOfDocuments()
|
||||
{
|
||||
return $this->owner->Title . ' (' . $this->owner->Documents()->Count() . ')';
|
||||
return $this->owner->Title . ' (' . $this->owner->getAllDocuments()->count() . ')';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Creates default taxonomy type records if they don't exist already
|
||||
*/
|
||||
class DMSTaxonomyTypeExtension extends DataExtension
|
||||
{
|
||||
/**
|
||||
* Create default taxonomy type records. Add records via YAML configuration (see taxonomy.yml):
|
||||
*
|
||||
* <code>
|
||||
* DMSTaxonomyTypeExtension:
|
||||
* default_records:
|
||||
* - Document
|
||||
* - PrivateDocument
|
||||
* </code>
|
||||
*/
|
||||
public function requireDefaultRecords()
|
||||
{
|
||||
$records = (array) Config::inst()->get(get_class($this), 'default_records');
|
||||
foreach ($records as $name) {
|
||||
$type = TaxonomyType::get()->filter('Name', $name)->first();
|
||||
if (!$type) {
|
||||
$type = TaxonomyType::create(array('Name' => $name));
|
||||
$type->write();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Combines form inputs into a key-value pair
|
||||
*/
|
||||
class DMSJsonField extends CompositeField
|
||||
{
|
||||
public function __construct($name, $children = null)
|
||||
{
|
||||
$this->setName($name);
|
||||
|
||||
if ($children instanceof FieldList || is_array($children)) {
|
||||
foreach ($children as $child) {
|
||||
$this->setChildName($child);
|
||||
}
|
||||
} else {
|
||||
$children = is_array(func_get_args()) ? func_get_args() : array();
|
||||
if (!empty($children)) {
|
||||
array_shift($children);
|
||||
}
|
||||
foreach ($children as $child) {
|
||||
$this->setChildName($child);
|
||||
}
|
||||
}
|
||||
parent::__construct($children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the child object
|
||||
*
|
||||
* @param FormField $child
|
||||
*/
|
||||
private function setChildName($child)
|
||||
{
|
||||
$child->setName("{$this->getName()}[{$child->getName()}]");
|
||||
}
|
||||
|
||||
public function hasData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override parent's behaviour as it's no longer required
|
||||
*
|
||||
* @param array $list
|
||||
* @param bool $saveableOnly
|
||||
*/
|
||||
public function collateDataFields(&$list, $saveableOnly = false)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively removed empty key-value pairs from $haystack
|
||||
*
|
||||
* @param $haystack
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function arrayFilterEmptyRecursive($haystack)
|
||||
{
|
||||
foreach ($haystack as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$haystack[$key] = $this->arrayFilterEmptyRecursive($haystack[$key]);
|
||||
}
|
||||
if (empty($haystack[$key])) {
|
||||
unset($haystack[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $haystack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides parent behaviour to remove empty elements
|
||||
*
|
||||
* @return mixed|null|string
|
||||
*/
|
||||
public function dataValue()
|
||||
{
|
||||
$result = null;
|
||||
if (is_array($this->value)) {
|
||||
$this->value = $this->arrayFilterEmptyRecursive($this->value);
|
||||
$result = (!empty($this->value)) ? Convert::array2json($this->value) : $result;
|
||||
} else {
|
||||
$result = parent::dataValue();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
if (is_string($value) && !empty($value)) {
|
||||
$value = Convert::json2array($value);
|
||||
} elseif (!is_array($value)) {
|
||||
$value = array($value);
|
||||
}
|
||||
|
||||
$pattern = "/^{$this->getName()}\[(.*)\]$/";
|
||||
foreach ($this->children as $c) {
|
||||
$title = $c->getName();
|
||||
preg_match($pattern, $title, $matches);
|
||||
if (!empty($matches[1]) && isset($value[$matches[1]])) {
|
||||
$c->setValue($value[$matches[1]]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -1,117 +1,22 @@
|
|||
<?php
|
||||
/**
|
||||
* Interface for a DMSDocument used in the Document Management System. A DMSDocument is create by storing a File object in an
|
||||
* instance of the DMSInterface. All write operations on the DMSDocument create a new relation, so we never need to
|
||||
* explicitly call the write() method on the DMSDocument DataObject
|
||||
* Interface for a DMSDocument used in the Document Management System. A DMSDocument is create by storing a File
|
||||
* object in an instance of the DMSInterface. All write operations on the DMSDocument create a new relation, so we
|
||||
* never need to explicitly call the write() method on the DMSDocument DataObject
|
||||
*/
|
||||
interface DMSDocumentInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Deletes the DMSDocument, its underlying file, as well as any tags related to this DMSDocument.
|
||||
*
|
||||
* @todo Can't be applied to classes which already implement the DataObjectInterface (naming conflict)
|
||||
*
|
||||
* @abstract
|
||||
* @return null
|
||||
*/
|
||||
// function delete();
|
||||
|
||||
/**
|
||||
* Associates this DMSDocument with a Page. This method does nothing if the association already exists.
|
||||
* This could be a simple wrapper around $myDoc->Pages()->add($myPage) to add a many_many relation
|
||||
* @abstract
|
||||
* @param $pageObject Page object to associate this DMSDocument with
|
||||
* @return null
|
||||
*/
|
||||
public function addPage($pageObject);
|
||||
|
||||
/**
|
||||
* Associates this DMSDocument with a set of Pages. This method loops through a set of page ids, and then associates this
|
||||
* DMSDocument with the individual Page with the each page id in the set
|
||||
* @abstract
|
||||
* @param $pageIDs array of page ids used for the page objects associate this DMSDocument with
|
||||
* @return null
|
||||
*/
|
||||
public function addPages($pageIDs);
|
||||
|
||||
/**
|
||||
* Removes the association between this DMSDocument and a Page. This method does nothing if the association does not exist.
|
||||
* @abstract
|
||||
* @param $pageObject Page object to remove the association to
|
||||
* @return mixed
|
||||
*/
|
||||
public function removePage($pageObject);
|
||||
|
||||
/**
|
||||
* Returns a list of the Page objects associated with this DMSDocument
|
||||
* @abstract
|
||||
* @return DataList
|
||||
*/
|
||||
public function getPages();
|
||||
|
||||
/**
|
||||
* Removes all associated Pages from the DMSDocument
|
||||
* @abstract
|
||||
* @return null
|
||||
*/
|
||||
public function removeAllPages();
|
||||
|
||||
/**
|
||||
* Adds a metadata tag to the DMSDocument. The tag has a category and a value.
|
||||
* Each category can have multiple values by default. So: addTag("fruit","banana") addTag("fruit", "apple") will add two items.
|
||||
* However, if the third parameter $multiValue is set to 'false', then all updates to a category only ever update a single value. So:
|
||||
* addTag("fruit","banana") addTag("fruit", "apple") would result in a single metadata tag: fruit->apple.
|
||||
* Can could be implemented as a key/value store table (although it is more like category/value, because the
|
||||
* same category can occur multiple times)
|
||||
* @abstract
|
||||
* @param $category String of a metadata category to add (required)
|
||||
* @param $value String of a metadata value to add (required)
|
||||
* @param bool $multiValue Boolean that determines if the category is multi-value or single-value (optional)
|
||||
* @return null
|
||||
*/
|
||||
public function addTag($category, $value, $multiValue = true);
|
||||
|
||||
/**
|
||||
* Fetches all tags associated with this DMSDocument within a given category. If a value is specified this method
|
||||
* tries to fetch that specific tag.
|
||||
* @abstract
|
||||
* @param $category String of the metadata category to get
|
||||
* @param null $value String of the value of the tag to get
|
||||
* @return array of Strings of all the tags or null if there is no match found
|
||||
*/
|
||||
public function getTagsList($category, $value = null);
|
||||
|
||||
/**
|
||||
* Removes a tag from the DMSDocument. If you only set a category, then all values in that category are deleted.
|
||||
* If you specify both a category and a value, then only that single category/value pair is deleted.
|
||||
* Nothing happens if the category or the value do not exist.
|
||||
* @abstract
|
||||
* @param $category Category to remove (required)
|
||||
* @param null $value Value to remove (optional)
|
||||
* @return null
|
||||
*/
|
||||
public function removeTag($category, $value = null);
|
||||
|
||||
/**
|
||||
* Deletes all tags associated with this DMSDocument.
|
||||
* @abstract
|
||||
* @return null
|
||||
*/
|
||||
public function removeAllTags();
|
||||
|
||||
/**
|
||||
* Returns a link to download this DMSDocument from the DMS store
|
||||
* @abstract
|
||||
* @return String
|
||||
*/
|
||||
public function getLink();
|
||||
|
||||
|
||||
/**
|
||||
* Return the extension of the file associated with the document
|
||||
*/
|
||||
public function getExtension();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the size of the file type in an appropriate format.
|
||||
*
|
||||
|
@ -139,14 +44,12 @@ interface DMSDocumentInterface
|
|||
* Hides the DMSDocument, so it does not show up when getByPage($myPage) is called
|
||||
* (without specifying the $showEmbargoed = true parameter). This is similar to expire, except that this method
|
||||
* should be used to hide DMSDocuments that have not yet gone live.
|
||||
* @abstract
|
||||
* @return null
|
||||
*/
|
||||
public function embargoIndefinitely();
|
||||
|
||||
/**
|
||||
* Returns if this is DMSDocument is embargoed or expired.
|
||||
* @abstract
|
||||
* @return bool True or False depending on whether this DMSDocument is embargoed or expired
|
||||
*/
|
||||
public function isHidden();
|
||||
|
@ -154,7 +57,6 @@ interface DMSDocumentInterface
|
|||
|
||||
/**
|
||||
* Returns if this is DMSDocument is embargoed.
|
||||
* @abstract
|
||||
* @return bool True or False depending on whether this DMSDocument is embargoed
|
||||
*/
|
||||
public function isEmbargoed();
|
||||
|
@ -162,7 +64,6 @@ interface DMSDocumentInterface
|
|||
/**
|
||||
* Hides the DMSDocument, so it does not show up when getByPage($myPage) is called. Automatically un-hides the
|
||||
* DMSDocument at a specific date.
|
||||
* @abstract
|
||||
* @param $datetime String date time value when this DMSDocument should expire
|
||||
* @return null
|
||||
*/
|
||||
|
@ -176,21 +77,18 @@ interface DMSDocumentInterface
|
|||
|
||||
/**
|
||||
* Clears any previously set embargos, so the DMSDocument always shows up in all queries.
|
||||
* @abstract
|
||||
* @return null
|
||||
*/
|
||||
public function clearEmbargo();
|
||||
|
||||
/**
|
||||
* Returns if this is DMSDocument is expired.
|
||||
* @abstract
|
||||
* @return bool True or False depending on whether this DMSDocument is expired
|
||||
*/
|
||||
public function isExpired();
|
||||
|
||||
/**
|
||||
* Hides the DMSDocument at a specific date, so it does not show up when getByPage($myPage) is called.
|
||||
* @abstract
|
||||
* @param $datetime String date time value when this DMSDocument should expire
|
||||
* @return null
|
||||
*/
|
||||
|
@ -198,7 +96,6 @@ interface DMSDocumentInterface
|
|||
|
||||
/**
|
||||
* Clears any previously set expiry.
|
||||
* @abstract
|
||||
* @return null
|
||||
*/
|
||||
public function clearExpiry();
|
||||
|
@ -208,7 +105,6 @@ interface DMSDocumentInterface
|
|||
/**
|
||||
* Returns a DataList of all previous Versions of this DMSDocument (check the LastEdited date of each
|
||||
* object to find the correct one)
|
||||
* @abstract
|
||||
* @return DataList List of DMSDocument objects
|
||||
*/
|
||||
public function getVersions();
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
*/
|
||||
interface DMSInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Factory method that returns an instance of the DMS. This could be any class that implements the DMSInterface.
|
||||
* @static
|
||||
|
@ -28,18 +27,6 @@ interface DMSInterface
|
|||
*/
|
||||
public function storeDocument($file);
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns a number of Document objects based on the a search by tags. You can search by category alone,
|
||||
* by tag value alone, or by both. I.e: getByTag("fruits",null); getByTag(null,"banana"); getByTag("fruits","banana")
|
||||
* @abstract
|
||||
* @param null $category The metadata category to search for
|
||||
* @param null $value The metadata value to search for
|
||||
* @param bool $showEmbargoed Boolean that specifies if embargoed documents should be included in results
|
||||
* @return DMSDocumentInterface
|
||||
*/
|
||||
public function getByTag($category = null, $value = null, $showEmbargoed = false);
|
||||
|
||||
/**
|
||||
* Returns a number of Document objects that match a full-text search of the Documents and their contents
|
||||
* (if contents is searchable and compatible search module is installed - e.g. FullTextSearch module)
|
||||
|
@ -52,11 +39,19 @@ interface DMSInterface
|
|||
|
||||
|
||||
/**
|
||||
* Returns a list of Document objects associated with a Page
|
||||
* @abstract
|
||||
* @param $page SiteTree to fetch the associated Documents from
|
||||
* @param bool $showEmbargoed Boolean that specifies if embargoed documents should be included in results
|
||||
* @return DataList Document list associated with the Page
|
||||
* Returns a list of Document objects associated with a Page via intermediary document sets
|
||||
*
|
||||
* @param SiteTree $page SiteTree to fetch the associated Documents from
|
||||
* @param bool $showEmbargoed Boolean that specifies if embargoed documents should be included in results
|
||||
* @return ArrayList Document list associated with the Page
|
||||
*/
|
||||
public function getByPage($page, $showEmbargoed = false);
|
||||
public function getByPage(SiteTree $page, $showEmbargoed = false);
|
||||
|
||||
/**
|
||||
* Returns a list of Document Set objects associated with a Page
|
||||
*
|
||||
* @param SiteTree $page SiteTree to fetch the associated Document Sets from
|
||||
* @return ArrayList Document list associated with the Page
|
||||
*/
|
||||
public function getDocumentSetsByPage(SiteTree $page);
|
||||
}
|
||||
|
|
|
@ -2,55 +2,79 @@
|
|||
|
||||
/**
|
||||
* @package dms
|
||||
*
|
||||
* @property Varchar Filename
|
||||
* @property Varchar Folder
|
||||
* @property Varchar Title
|
||||
* @property Text Description
|
||||
* @property int ViewCount
|
||||
* @property Boolean EmbargoedIndefinitely
|
||||
* @property Boolean EmbargoedUntilPublished
|
||||
* @property DateTime EmbargoedUntilDate
|
||||
* @property DateTime ExpireAtDate
|
||||
* @property Enum DownloadBehavior
|
||||
* @property Enum CanViewType Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone')
|
||||
* @property Enum CanEditType Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')
|
||||
*
|
||||
* @method ManyManyList RelatedDocuments
|
||||
* @method ManyManyList ViewerGroups
|
||||
* @method ManyManyList EditorGroups
|
||||
*
|
||||
* @method Member CreatedBy
|
||||
* @property Int CreatedByID
|
||||
* @method Member LastEditedBy
|
||||
* @property Int LastEditedByID
|
||||
*
|
||||
*/
|
||||
class DMSDocument extends DataObject implements DMSDocumentInterface
|
||||
{
|
||||
|
||||
private static $db = array(
|
||||
"Filename" => "Varchar(255)", // eg. 3469~2011-energysaving-report.pdf
|
||||
"Folder" => "Varchar(255)", // eg. 0
|
||||
"Title" => 'Varchar(1024)', // eg. "Energy Saving Report for Year 2011, New Zealand LandCorp"
|
||||
"Description" => 'Text',
|
||||
"ViewCount" => 'Int',
|
||||
"LastChanged" => 'SS_DateTime', //when this document's file was created or last replaced (small changes like updating title don't count)
|
||||
|
||||
"EmbargoedIndefinitely" => 'Boolean(false)',
|
||||
"EmbargoedUntilPublished" => 'Boolean(false)',
|
||||
"EmbargoedUntilDate" => 'SS_DateTime',
|
||||
"ExpireAtDate" => 'SS_DateTime',
|
||||
"DownloadBehavior" => 'Enum(array("open","download"), "download")',
|
||||
"CanViewType" => "Enum('Anyone, LoggedInUsers, OnlyTheseUsers', 'Anyone')",
|
||||
"CanEditType" => "Enum('LoggedInUsers, OnlyTheseUsers', 'LoggedInUsers')",
|
||||
);
|
||||
|
||||
private static $belongs_many_many = array(
|
||||
'Sets' => 'DMSDocumentSet'
|
||||
);
|
||||
|
||||
private static $has_one = array(
|
||||
'CoverImage' => 'Image',
|
||||
'CreatedBy' => 'Member',
|
||||
'LastEditedBy' => 'Member',
|
||||
);
|
||||
|
||||
private static $many_many = array(
|
||||
'Pages' => 'SiteTree',
|
||||
'Tags' => 'DMSTag'
|
||||
);
|
||||
|
||||
private static $many_many_extraFields = array(
|
||||
'Pages' => array(
|
||||
'DocumentSort' => 'Int'
|
||||
)
|
||||
'RelatedDocuments' => 'DMSDocument',
|
||||
'ViewerGroups' => 'Group',
|
||||
'EditorGroups' => 'Group',
|
||||
);
|
||||
|
||||
private static $display_fields = array(
|
||||
'ID' => 'ID',
|
||||
'Title' => 'Title',
|
||||
'FilenameWithoutID' => 'Filename',
|
||||
'LastChanged' => 'LastChanged'
|
||||
'LastEdited' => 'Last Edited'
|
||||
);
|
||||
|
||||
private static $singular_name = 'Document';
|
||||
|
||||
private static $plural_name = 'Documents';
|
||||
|
||||
private static $searchable_fields = array(
|
||||
'ID' => array(
|
||||
'filter' => 'ExactMatchFilter',
|
||||
'field' => 'NumericField'
|
||||
),
|
||||
'Title',
|
||||
'Filename',
|
||||
'LastChanged'
|
||||
private static $summary_fields = array(
|
||||
'Filename' => 'Filename',
|
||||
'Title' => 'Title',
|
||||
'getRelatedPages.count' => 'Page Use',
|
||||
'ViewCount' => 'ViewCount',
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -60,10 +84,20 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
private static $default_download_behaviour = 'download';
|
||||
|
||||
/**
|
||||
* @param Member $member
|
||||
* A key value map of the "actions" tabs that will be added to the CMS fields
|
||||
*
|
||||
* @return boolean
|
||||
* @var array
|
||||
*/
|
||||
protected $actionTasks = array(
|
||||
'embargo' => 'Embargo',
|
||||
'expiry' => 'Expiry',
|
||||
'replace' => 'Replace',
|
||||
'find-usage' => 'Usage',
|
||||
'find-references' => 'References',
|
||||
'find-relateddocuments' => 'Related Documents',
|
||||
'permissions' => 'Permissions'
|
||||
);
|
||||
|
||||
public function canView($member = null)
|
||||
{
|
||||
if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
|
||||
|
@ -79,18 +113,33 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
}
|
||||
}
|
||||
|
||||
if ($member && $member->ID) {
|
||||
if (!$this->CanViewType || $this->CanViewType == 'Anyone') {
|
||||
return true;
|
||||
}
|
||||
if ($member && Permission::checkMember($member, array(
|
||||
'ADMIN',
|
||||
'SITETREE_EDIT_ALL',
|
||||
'SITETREE_VIEW_ALL',
|
||||
))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
if ($this->isHidden()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->CanViewType == 'LoggedInUsers') {
|
||||
return $member && $member->exists();
|
||||
}
|
||||
|
||||
if ($this->CanViewType == 'OnlyTheseUsers' && $this->ViewerGroups()->count()) {
|
||||
return ($member && $member->inGroups($this->ViewerGroups()) || $this->canEdit($member));
|
||||
}
|
||||
|
||||
return $this->canEdit($member);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Member $member
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canEdit($member = null)
|
||||
{
|
||||
if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
|
||||
|
@ -105,7 +154,20 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
}
|
||||
}
|
||||
|
||||
return $this->canView();
|
||||
// Do early admin check
|
||||
if ($member && Permission::checkMember($member, array('ADMIN','SITETREE_EDIT_ALL'))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->CanEditType === 'LoggedInUsers') {
|
||||
return $member && $member->exists();
|
||||
}
|
||||
|
||||
if ($this->CanEditType === 'OnlyTheseUsers' && $this->EditorGroups()->count()) {
|
||||
return $member && $member->inGroups($this->EditorGroups());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -127,7 +189,14 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
}
|
||||
}
|
||||
|
||||
return $this->canView();
|
||||
// Do early admin check
|
||||
if ($member &&
|
||||
Permission::checkMember($member, array('CMS_ACCESS_DMSDocumentAdmin'))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->canEdit($member);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,101 +218,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
}
|
||||
}
|
||||
|
||||
return $this->canView();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Associates this document with a Page. This method does nothing if the
|
||||
* association already exists.
|
||||
*
|
||||
* This could be a simple wrapper around $myDoc->Pages()->add($myPage) to
|
||||
* add a many_many relation.
|
||||
*
|
||||
* @param SiteTree $pageObject Page object to associate this Document with
|
||||
*
|
||||
* @return DMSDocument
|
||||
*/
|
||||
public function addPage($pageObject)
|
||||
{
|
||||
$this->Pages()->add($pageObject);
|
||||
|
||||
DB::query("UPDATE \"DMSDocument_Pages\" SET \"DocumentSort\"=\"DocumentSort\"+1 WHERE \"SiteTreeID\" = $pageObject->ID");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates this DMSDocument with a set of Pages. This method loops
|
||||
* through a set of page ids, and then associates this DMSDocument with the
|
||||
* individual Page with the each page id in the set.
|
||||
*
|
||||
* @param array $pageIDs
|
||||
*
|
||||
* @return DMSDocument
|
||||
*/
|
||||
public function addPages($pageIDs)
|
||||
{
|
||||
foreach ($pageIDs as $id) {
|
||||
$pageObject = DataObject::get_by_id("SiteTree", $id);
|
||||
|
||||
if ($pageObject && $pageObject->exists()) {
|
||||
$this->addPage($pageObject);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the association between this Document and a Page. This method
|
||||
* does nothing if the association does not exist.
|
||||
*
|
||||
* @param SiteTree $pageObject Page object to remove the association to
|
||||
*
|
||||
* @return DMSDocument
|
||||
*/
|
||||
public function removePage($pageObject)
|
||||
{
|
||||
$this->Pages()->remove($pageObject);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see getPages()
|
||||
*
|
||||
* @return DataList
|
||||
*/
|
||||
public function Pages()
|
||||
{
|
||||
$pages = $this->getManyManyComponents('Pages');
|
||||
$this->extend('updatePages', $pages);
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the Page objects associated with this Document.
|
||||
*
|
||||
* @return DataList
|
||||
*/
|
||||
public function getPages()
|
||||
{
|
||||
return $this->Pages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all associated Pages from the DMSDocument
|
||||
*
|
||||
* @return DMSDocument
|
||||
*/
|
||||
public function removeAllPages()
|
||||
{
|
||||
$this->Pages()->removeAll();
|
||||
|
||||
return $this;
|
||||
return $this->canEdit($member);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -260,173 +235,8 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
$this->ViewCount = $count;
|
||||
|
||||
DB::query("UPDATE \"DMSDocument\" SET \"ViewCount\"='$count' WHERE \"ID\"={$this->ID}");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a metadata tag to the Document. The tag has a category and a value.
|
||||
*
|
||||
* Each category can have multiple values by default. So:
|
||||
* addTag("fruit","banana") addTag("fruit", "apple") will add two items.
|
||||
*
|
||||
* However, if the third parameter $multiValue is set to 'false', then all
|
||||
* updates to a category only ever update a single value. So:
|
||||
* addTag("fruit","banana") addTag("fruit", "apple") would result in a
|
||||
* single metadata tag: fruit->apple.
|
||||
*
|
||||
* Can could be implemented as a key/value store table (although it is more
|
||||
* like category/value, because the same category can occur multiple times)
|
||||
*
|
||||
* @param string $category of a metadata category to add (required)
|
||||
* @param string $value of a metadata value to add (required)
|
||||
* @param bool $multiValue Boolean that determines if the category is
|
||||
* multi-value or single-value (optional)
|
||||
*
|
||||
* @return DMSDocument
|
||||
*/
|
||||
public function addTag($category, $value, $multiValue = true)
|
||||
{
|
||||
if ($multiValue) {
|
||||
//check for a duplicate tag, don't add the duplicate
|
||||
$currentTag = $this->Tags()->filter(array('Category' => $category, 'Value' => $value));
|
||||
if ($currentTag->Count() == 0) {
|
||||
//multi value tag
|
||||
$tag = new DMSTag();
|
||||
$tag->Category = $category;
|
||||
$tag->Value = $value;
|
||||
$tag->MultiValue = true;
|
||||
$tag->write();
|
||||
$tag->Documents()->add($this);
|
||||
} else {
|
||||
//add the relation between the tag and document
|
||||
foreach ($currentTag as $tagObj) {
|
||||
$tagObj->Documents()->add($this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//single value tag
|
||||
$currentTag = $this->Tags()->filter(array('Category' => $category));
|
||||
$tag = null;
|
||||
if ($currentTag->Count() == 0) {
|
||||
//create the single-value tag
|
||||
$tag = new DMSTag();
|
||||
$tag->Category = $category;
|
||||
$tag->Value = $value;
|
||||
$tag->MultiValue = false;
|
||||
$tag->write();
|
||||
} else {
|
||||
//update the single value tag
|
||||
$tag = $currentTag->first();
|
||||
$tag->Value = $value;
|
||||
$tag->MultiValue = false;
|
||||
$tag->write();
|
||||
}
|
||||
|
||||
// regardless of whether we created a new tag or are just updating an
|
||||
// existing one, add the relation
|
||||
$tag->Documents()->add($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $category
|
||||
* @param string $value
|
||||
*
|
||||
* @return DataList
|
||||
*/
|
||||
protected function getTagsObjects($category, $value = null)
|
||||
{
|
||||
$valueFilter = array("Category" => $category);
|
||||
if (!empty($value)) {
|
||||
$valueFilter['Value'] = $value;
|
||||
}
|
||||
|
||||
$tags = $this->Tags()->filter($valueFilter);
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all tags associated with this DMSDocument within a given
|
||||
* category. If a value is specified this method tries to fetch that
|
||||
* specific tag.
|
||||
*
|
||||
* @param string $category metadata category to get
|
||||
* @param string $value value of the tag to get
|
||||
*
|
||||
* @return array Strings of all the tags or null if there is no match found
|
||||
*/
|
||||
public function getTagsList($category, $value = null)
|
||||
{
|
||||
$tags = $this->getTagsObjects($category, $value);
|
||||
|
||||
$returnArray = null;
|
||||
|
||||
if ($tags->Count() > 0) {
|
||||
$returnArray = array();
|
||||
|
||||
foreach ($tags as $t) {
|
||||
$returnArray[] = $t->Value;
|
||||
}
|
||||
}
|
||||
|
||||
return $returnArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a tag from the Document. If you only set a category, then all
|
||||
* values in that category are deleted.
|
||||
*
|
||||
* If you specify both a category and a value, then only that single
|
||||
* category/value pair is deleted.
|
||||
*
|
||||
* Nothing happens if the category or the value do not exist.
|
||||
*
|
||||
* @param string $category Category to remove
|
||||
* @param string $value Value to remove
|
||||
*
|
||||
* @return DMSDocument
|
||||
*/
|
||||
public function removeTag($category, $value = null)
|
||||
{
|
||||
$tags = $this->getTagsObjects($category, $value);
|
||||
|
||||
if ($tags->Count() > 0) {
|
||||
foreach ($tags as $t) {
|
||||
$documentList = $t->Documents();
|
||||
|
||||
//remove the relation between the tag and the document
|
||||
$documentList->remove($this);
|
||||
|
||||
//delete the entire tag if it has no relations left
|
||||
if ($documentList->Count() == 0) {
|
||||
$t->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all tags associated with this Document.
|
||||
*
|
||||
* @return DMSDocument
|
||||
*/
|
||||
public function removeAllTags()
|
||||
{
|
||||
$allTags = $this->Tags();
|
||||
|
||||
foreach ($allTags as $tag) {
|
||||
$documentlist = $tag->Documents();
|
||||
$documentlist->remove($this);
|
||||
if ($tag->Documents()->Count() == 0) {
|
||||
$tag->delete();
|
||||
}
|
||||
$this->extend('trackView');
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -434,12 +244,31 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
|
||||
/**
|
||||
* Returns a link to download this document from the DMS store.
|
||||
* Alternatively a basic javascript alert will be shown should the user not have view permissions. An extension
|
||||
* point for this was also added.
|
||||
*
|
||||
* To extend use the following from within an Extension subclass:
|
||||
*
|
||||
* <code>
|
||||
* public function updateGetLink($result)
|
||||
* {
|
||||
* // Do something here
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLink()
|
||||
{
|
||||
return Controller::join_links(Director::baseURL(), 'dmsdocument/'.$this->ID);
|
||||
$urlSegment = sprintf('%d-%s', $this->ID, URLSegmentFilter::create()->filter($this->getTitle()));
|
||||
$result = Controller::join_links(Director::baseURL(), 'dmsdocument/' . $urlSegment);
|
||||
if (!$this->canView()) {
|
||||
$result = sprintf("javascript:alert('%s')", $this->getPermissionDeniedReason());
|
||||
}
|
||||
|
||||
$this->extend('updateGetLink', $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -670,7 +499,8 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
public function getFullPath()
|
||||
{
|
||||
if ($this->Filename) {
|
||||
return DMS::get_dms_path() . DIRECTORY_SEPARATOR . $this->Folder . DIRECTORY_SEPARATOR . $this->Filename;
|
||||
return DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR
|
||||
. $this->Folder . DIRECTORY_SEPARATOR . $this->Filename;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -681,13 +511,12 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFileName()
|
||||
public function getFilename()
|
||||
{
|
||||
if ($this->getField('Filename')) {
|
||||
return $this->getField('Filename');
|
||||
} else {
|
||||
return ASSETS_DIR . '/';
|
||||
}
|
||||
return ASSETS_DIR . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -700,6 +529,8 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
|
||||
|
||||
/**
|
||||
* Returns the filename of a document without the prefix, e.g. 0~filename.jpg -> filename.jpg
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFilenameWithoutID()
|
||||
|
@ -715,21 +546,17 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
*/
|
||||
public function getStorageFolder()
|
||||
{
|
||||
return DMS::get_dms_path() . DIRECTORY_SEPARATOR . DMS::get_storage_folder($this->ID);
|
||||
return DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . DMS::inst()->getStorageFolder($this->ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the DMSDocument, its underlying file, as well as any tags related
|
||||
* to this DMSDocument. Also calls the parent DataObject's delete method in
|
||||
* Deletes the DMSDocument and its underlying file. Also calls the parent DataObject's delete method in
|
||||
* order to complete an cascade.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
// remove tags
|
||||
$this->removeAllTags();
|
||||
|
||||
// delete the file (and previous versions of files)
|
||||
$filesToDelete = array();
|
||||
$storageFolder = $this->getStorageFolder();
|
||||
|
@ -756,8 +583,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
}
|
||||
}
|
||||
|
||||
$this->removeAllPages();
|
||||
|
||||
// get rid of any versions have saved for this DMSDocument, too
|
||||
if (DMSDocument_versions::$enable_versions) {
|
||||
$versions = $this->getVersions();
|
||||
|
@ -769,15 +594,13 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
}
|
||||
}
|
||||
|
||||
parent::delete();
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Relate an existing file on the filesystem to the document.
|
||||
*
|
||||
* Copies the file to the new destination, as defined in {@link get_DMS_path()}.
|
||||
* Copies the file to the new destination, as defined in {@link DMS::getStoragePath()}.
|
||||
*
|
||||
* @param string $filePath Path to file, relative to webroot.
|
||||
*
|
||||
|
@ -792,10 +615,10 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
// calculate all the path to copy the file to
|
||||
$fromFilename = basename($filePath);
|
||||
$toFilename = $this->ID. '~' . $fromFilename; //add the docID to the start of the Filename
|
||||
$toFolder = DMS::get_storage_folder($this->ID);
|
||||
$toPath = DMS::get_dms_path() . DIRECTORY_SEPARATOR . $toFolder . DIRECTORY_SEPARATOR . $toFilename;
|
||||
$toFolder = DMS::inst()->getStorageFolder($this->ID);
|
||||
$toPath = DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . $toFolder . DIRECTORY_SEPARATOR . $toFilename;
|
||||
|
||||
DMS::create_storage_folder(DMS::get_dms_path() . DIRECTORY_SEPARATOR . $toFolder);
|
||||
DMS::inst()->createStorageFolder(DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . $toFolder);
|
||||
|
||||
//copy the file into place
|
||||
$fromPath = BASE_PATH . DIRECTORY_SEPARATOR . $filePath;
|
||||
|
@ -823,7 +646,6 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
$this->Title = basename($filePath, '.'.$extension);
|
||||
}
|
||||
|
||||
$this->LastChanged = SS_Datetime::now()->Rfc2822();
|
||||
$this->write();
|
||||
|
||||
return $this;
|
||||
|
@ -840,7 +662,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
*/
|
||||
public function replaceDocument($file)
|
||||
{
|
||||
$filePath = DMS::transform_file_to_file_path($file);
|
||||
$filePath = DMS::inst()->transformFileToFilePath($file);
|
||||
$doc = $this->storeDocument($filePath); // replace the document
|
||||
|
||||
return $doc;
|
||||
|
@ -902,8 +724,8 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
public function getCMSFields()
|
||||
{
|
||||
//include JS to handling showing and hiding of bottom "action" tabs
|
||||
Requirements::javascript(DMS_DIR.'/javascript/DMSDocumentCMSFields.js');
|
||||
Requirements::css(DMS_DIR.'/css/DMSDocumentCMSFields.css');
|
||||
Requirements::javascript(DMS_DIR . '/javascript/DMSDocumentCMSFields.js');
|
||||
Requirements::css(DMS_DIR . '/dist/css/cmsbundle.css');
|
||||
|
||||
$fields = new FieldList(); //don't use the automatic scaffolding, it is slow and unnecessary here
|
||||
|
||||
|
@ -916,8 +738,14 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
$fieldsTop = $this->getFieldsForFile($relationList->count());
|
||||
$fields->add($fieldsTop);
|
||||
|
||||
$fields->add(new TextField('Title', 'Title'));
|
||||
$fields->add(new TextareaField('Description', 'Description'));
|
||||
$fields->add(TextField::create('Title', _t('DMSDocument.TITLE', 'Title')));
|
||||
$fields->add(TextareaField::create('Description', _t('DMSDocument.DESCRIPTION', 'Description')));
|
||||
|
||||
$coverImageField = UploadField::create('CoverImage', _t('DMSDocument.COVERIMAGE', 'Cover Image'));
|
||||
$coverImageField->getValidator()->setAllowedExtensions(array('jpg', 'jpeg', 'png', 'gif'));
|
||||
$coverImageField->setConfig('allowedMaxFileNumber', 1);
|
||||
$fields->add($coverImageField);
|
||||
|
||||
|
||||
$downloadBehaviorSource = array(
|
||||
'open' => _t('DMSDocument.OPENINBROWSER', 'Open in browser'),
|
||||
|
@ -926,8 +754,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
$defaultDownloadBehaviour = Config::inst()->get('DMSDocument', 'default_download_behaviour');
|
||||
if (!isset($downloadBehaviorSource[$defaultDownloadBehaviour])) {
|
||||
user_error('Default download behaviour "' . $defaultDownloadBehaviour . '" not supported.', E_USER_WARNING);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$downloadBehaviorSource[$defaultDownloadBehaviour] .= ' (' . _t('DMSDocument.DEFAULT', 'default') . ')';
|
||||
}
|
||||
|
||||
|
@ -938,7 +765,10 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
$downloadBehaviorSource,
|
||||
$defaultDownloadBehaviour
|
||||
)
|
||||
->setDescription('How the visitor will view this file. <strong>Open in browser</strong> allows files to be opened in a new tab.')
|
||||
->setDescription(
|
||||
'How the visitor will view this file. <strong>Open in browser</strong> '
|
||||
. 'allows files to be opened in a new tab.'
|
||||
)
|
||||
);
|
||||
|
||||
//create upload field to replace document
|
||||
|
@ -958,12 +788,12 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
|
||||
$gridFieldConfig->getComponentByType('GridFieldDataColumns')
|
||||
->setDisplayFields(array(
|
||||
'Title'=>'Title',
|
||||
'ClassName'=>'Page Type',
|
||||
'ID'=>'Page ID'
|
||||
'Title' => 'Title',
|
||||
'ClassName' => 'Page Type',
|
||||
'ID' => 'Page ID'
|
||||
))
|
||||
->setFieldFormatting(array(
|
||||
'Title'=>sprintf(
|
||||
'Title' => sprintf(
|
||||
'<a class=\"cms-panel-link\" href=\"%s/$ID\">$Title</a>',
|
||||
singleton('CMSPageEditController')->Link('show')
|
||||
)
|
||||
|
@ -972,7 +802,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
$pagesGrid = GridField::create(
|
||||
'Pages',
|
||||
_t('DMSDocument.RelatedPages', 'Related Pages'),
|
||||
$this->Pages(),
|
||||
$this->getRelatedPages(),
|
||||
$gridFieldConfig
|
||||
);
|
||||
|
||||
|
@ -990,9 +820,14 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
new GridFieldDataColumns(),
|
||||
new GridFieldPaginator(30)
|
||||
);
|
||||
$versionsGridFieldConfig->getComponentByType('GridFieldDataColumns')->setDisplayFields(Config::inst()->get('DMSDocument_versions', 'display_fields'))
|
||||
->setFieldCasting(array('LastChanged'=>"Datetime->Ago"))
|
||||
->setFieldFormatting(array('FilenameWithoutID'=>'<a target=\'_blank\' class=\'file-url\' href=\'$Link\'>$FilenameWithoutID</a>'));
|
||||
|
||||
$versionsGridFieldConfig->getComponentByType('GridFieldDataColumns')
|
||||
->setDisplayFields(Config::inst()->get('DMSDocument_versions', 'display_fields'))
|
||||
->setFieldFormatting(
|
||||
array(
|
||||
'FilenameWithoutID' => '<a target=\"_blank\" class=\"file-url\" href=\"$Link\">$FilenameWithoutID</a>'
|
||||
)
|
||||
);
|
||||
|
||||
$versionsGrid = GridField::create(
|
||||
'Versions',
|
||||
|
@ -1000,21 +835,9 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
$this->getVersions(),
|
||||
$versionsGridFieldConfig
|
||||
);
|
||||
$extraTasks .= '<li class="ss-ui-button" data-panel="find-versions">Versions</li>';
|
||||
//$extraFields = $versionsGrid->addExtraClass('find-versions');
|
||||
$this->addActionPanelTask('find-versions', 'Versions');
|
||||
}
|
||||
|
||||
$fields->add(new LiteralField('BottomTaskSelection',
|
||||
'<div id="Actions" class="field actions"><label class="left">Actions</label><ul>'.
|
||||
'<li class="ss-ui-button" data-panel="embargo">Embargo</li>'.
|
||||
'<li class="ss-ui-button" data-panel="expiry">Expiry</li>'.
|
||||
'<li class="ss-ui-button" data-panel="replace">Replace</li>'.
|
||||
'<li class="ss-ui-button" data-panel="find-usage">Usage</li>'.
|
||||
'<li class="ss-ui-button" data-panel="find-references">References</li>'.
|
||||
$extraTasks.
|
||||
'</ul></div>'
|
||||
));
|
||||
|
||||
$embargoValue = 'None';
|
||||
if ($this->EmbargoedIndefinitely) {
|
||||
$embargoValue = 'Indefinitely';
|
||||
|
@ -1023,78 +846,127 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
} elseif (!empty($this->EmbargoedUntilDate)) {
|
||||
$embargoValue = 'Date';
|
||||
}
|
||||
$embargo = new OptionsetField('Embargo', 'Embargo', array('None'=>'None', 'Published'=>'Hide document until page is published', 'Indefinitely'=>'Hide document indefinitely', 'Date'=>'Hide until set date'), $embargoValue);
|
||||
$embargo = new OptionsetField(
|
||||
'Embargo',
|
||||
_t('DMSDocument.EMBARGO', 'Embargo'),
|
||||
array(
|
||||
'None' => _t('DMSDocument.EMBARGO_NONE', 'None'),
|
||||
'Published' => _t('DMSDocument.EMBARGO_PUBLISHED', 'Hide document until page is published'),
|
||||
'Indefinitely' => _t('DMSDocument.EMBARGO_INDEFINITELY', 'Hide document indefinitely'),
|
||||
'Date' => _t('DMSDocument.EMBARGO_DATE', 'Hide until set date')
|
||||
),
|
||||
$embargoValue
|
||||
);
|
||||
$embargoDatetime = DatetimeField::create('EmbargoedUntilDate', '');
|
||||
$embargoDatetime->getDateField()->setConfig('showcalendar', true)->setConfig('dateformat', 'dd-MM-yyyy')->setConfig('datavalueformat', 'dd-MM-yyyy');
|
||||
$embargoDatetime->getDateField()
|
||||
->setConfig('showcalendar', true)
|
||||
->setConfig('dateformat', 'dd-MM-yyyy')
|
||||
->setConfig('datavalueformat', 'dd-MM-yyyy');
|
||||
|
||||
$expiryValue = 'None';
|
||||
if (!empty($this->ExpireAtDate)) {
|
||||
$expiryValue = 'Date';
|
||||
}
|
||||
$expiry = new OptionsetField('Expiry', 'Expiry', array('None'=>'None', 'Date'=>'Set document to expire on'), $expiryValue);
|
||||
$expiry = new OptionsetField(
|
||||
'Expiry',
|
||||
'Expiry',
|
||||
array(
|
||||
'None' => 'None',
|
||||
'Date' => 'Set document to expire on'
|
||||
),
|
||||
$expiryValue
|
||||
);
|
||||
$expiryDatetime = DatetimeField::create('ExpireAtDate', '');
|
||||
$expiryDatetime->getDateField()->setConfig('showcalendar', true)->setConfig('dateformat', 'dd-MM-yyyy')->setConfig('datavalueformat', 'dd-MM-yyyy');
|
||||
$expiryDatetime->getDateField()
|
||||
->setConfig('showcalendar', true)
|
||||
->setConfig('dateformat', 'dd-MM-yyyy')
|
||||
->setConfig('datavalueformat', 'dd-MM-yyyy');
|
||||
|
||||
// This adds all the actions details into a group.
|
||||
// Embargo, History, etc to go in here
|
||||
// These are toggled on and off via the Actions Buttons above
|
||||
// exit('hit');
|
||||
$actionsPanel = FieldGroup::create(
|
||||
|
||||
FieldGroup::create(
|
||||
$embargo,
|
||||
$embargoDatetime
|
||||
)->addExtraClass('embargo'),
|
||||
|
||||
FieldGroup::create(
|
||||
$expiry,
|
||||
$expiryDatetime
|
||||
)->addExtraClass('expiry'),
|
||||
|
||||
FieldGroup::create(
|
||||
$uploadField
|
||||
)->addExtraClass('replace'),
|
||||
|
||||
FieldGroup::create(
|
||||
$pagesGrid
|
||||
)->addExtraClass('find-usage'),
|
||||
|
||||
FieldGroup::create(
|
||||
$referencesGrid
|
||||
)->addExtraClass('find-references'),
|
||||
|
||||
FieldGroup::create(
|
||||
$versionsGrid
|
||||
)->addExtraClass('find-versions')
|
||||
|
||||
FieldGroup::create($embargo, $embargoDatetime)->addExtraClass('embargo'),
|
||||
FieldGroup::create($expiry, $expiryDatetime)->addExtraClass('expiry'),
|
||||
FieldGroup::create($uploadField)->addExtraClass('replace'),
|
||||
FieldGroup::create($pagesGrid)->addExtraClass('find-usage'),
|
||||
FieldGroup::create($referencesGrid)->addExtraClass('find-references'),
|
||||
FieldGroup::create($this->getPermissionsActionPanel())->addExtraClass('permissions')
|
||||
);
|
||||
|
||||
$actionsPanel->setName("ActionsPanel");
|
||||
$actionsPanel->addExtraClass("DMSDocumentActionsPanel");
|
||||
|
||||
if ($this->canEdit()) {
|
||||
$actionsPanel->push(FieldGroup::create($versionsGrid)->addExtraClass('find-versions'));
|
||||
$actionsPanel->push(
|
||||
FieldGroup::create($this->getRelatedDocumentsGridField())->addExtraClass('find-relateddocuments')
|
||||
);
|
||||
} else {
|
||||
$this->removeActionPanelTask('find-relateddocuments')->removeActionPanelTask('find-versions');
|
||||
}
|
||||
$fields->add(LiteralField::create('BottomTaskSelection', $this->getActionTaskHtml()));
|
||||
$actionsPanel->setName('ActionsPanel');
|
||||
$actionsPanel->addExtraClass('dmsdocument-actionspanel');
|
||||
$fields->push($actionsPanel);
|
||||
|
||||
// $fields->add(FieldGroup::create(
|
||||
// FieldGroup::create(
|
||||
// $embargo,
|
||||
// $embargoDatetime
|
||||
// )->addExtraClass('embargo'),
|
||||
// FieldGroup::create(
|
||||
// $expiry,
|
||||
// $expiryDatetime
|
||||
// )->addExtraClass('expiry'),
|
||||
// $uploadField->addExtraClass('replace'),
|
||||
// $pagesGrid->addExtraClass('find-usage'),
|
||||
// $referencesGrid->addExtraClass('find-references'),
|
||||
// $extraFields
|
||||
// )->setName("ActionsPanel")->addExtraClass('dmsupload ss-uploadfield'));
|
||||
|
||||
|
||||
$this->extend('updateCMSFields', $fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds permissions selection fields to a composite field and returns so it can be used in the "actions panel"
|
||||
*
|
||||
* @return CompositeField
|
||||
*/
|
||||
public function getPermissionsActionPanel()
|
||||
{
|
||||
$fields = FieldList::create();
|
||||
$showFields = array(
|
||||
'CanViewType' => '',
|
||||
'ViewerGroups' => 'hide',
|
||||
'CanEditType' => '',
|
||||
'EditorGroups' => 'hide',
|
||||
);
|
||||
/** @var SiteTree $siteTree */
|
||||
$siteTree = singleton('SiteTree');
|
||||
$settingsFields = $siteTree->getSettingsFields();
|
||||
|
||||
foreach ($showFields as $name => $extraCss) {
|
||||
$compositeName = "Root.Settings.$name";
|
||||
/** @var FormField $field */
|
||||
if ($field = $settingsFields->fieldByName($compositeName)) {
|
||||
$field->addExtraClass($extraCss);
|
||||
$title = str_replace('page', 'document', $field->Title());
|
||||
$field->setTitle($title);
|
||||
|
||||
// Remove Inherited source option from DropdownField
|
||||
if ($field instanceof DropdownField) {
|
||||
$options = $field->getSource();
|
||||
unset($options['Inherit']);
|
||||
$field->setSource($options);
|
||||
}
|
||||
$fields->push($field);
|
||||
}
|
||||
}
|
||||
|
||||
$this->extend('updatePermissionsFields', $fields);
|
||||
|
||||
return CompositeField::create($fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a title to use on the frontend, preferably the "title", otherwise the filename without it's numeric ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
if ($this->getField('Title')) {
|
||||
return $this->getField('Title');
|
||||
}
|
||||
return $this->FilenameWithoutID;
|
||||
}
|
||||
|
||||
public function onBeforeWrite()
|
||||
{
|
||||
parent::onBeforeWrite();
|
||||
|
@ -1103,7 +975,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
//set the embargo options from the OptionSetField created in the getCMSFields method
|
||||
//do not write after clearing the embargo (write happens automatically)
|
||||
$savedDate = $this->EmbargoedUntilDate;
|
||||
$this->clearEmbargo(false); //clear all previous settings and re-apply them on save
|
||||
$this->clearEmbargo(false); // Clear all previous settings and re-apply them on save
|
||||
|
||||
if ($this->Embargo == 'Published') {
|
||||
$this->embargoUntilPublished(false);
|
||||
|
@ -1121,7 +993,30 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
$this->expireAtDate($this->ExpireAtDate, false);
|
||||
} else {
|
||||
$this->clearExpiry(false);
|
||||
} //clear all previous settings
|
||||
} // Clear all previous settings
|
||||
}
|
||||
|
||||
// Set user fields
|
||||
if ($currentUserID = Member::currentUserID()) {
|
||||
if (!$this->CreatedByID) {
|
||||
$this->CreatedByID = $currentUserID;
|
||||
}
|
||||
$this->LastEditedByID = $currentUserID;
|
||||
}
|
||||
|
||||
// make sure default DownloadBehavior is respected when initially writing document
|
||||
// in case the default in the enum is different than what's set in an outside config
|
||||
$defaultDownloadBehaviour = Config::inst()->get('DMSDocument', 'default_download_behaviour');
|
||||
if ($this->DownloadBehavior == null && !empty($defaultDownloadBehaviour)) {
|
||||
$possibleBehaviors = $this->dbObject('DownloadBehavior')
|
||||
->enumValues();
|
||||
|
||||
if (array_key_exists($defaultDownloadBehaviour, $possibleBehaviors)) {
|
||||
$behavior = $possibleBehaviors[$defaultDownloadBehaviour];
|
||||
if ($behavior) {
|
||||
$this->DownloadBehavior = $behavior;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1193,12 +1088,14 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
{
|
||||
$extension = $this->getExtension();
|
||||
|
||||
$previewField = new LiteralField("ImageFull",
|
||||
"<img id='thumbnailImage' class='thumbnail-preview' src='{$this->Icon($extension)}?r=" . rand(1, 100000) . "' alt='{$this->Title}' />\n"
|
||||
$previewField = new LiteralField(
|
||||
"ImageFull",
|
||||
"<img id='thumbnailImage' class='thumbnail-preview' src='{$this->Icon($extension)}?r="
|
||||
. rand(1, 100000) . "' alt='{$this->Title}' />\n"
|
||||
);
|
||||
|
||||
//count the number of pages this document is published on
|
||||
$publishedOnCount = $this->Pages()->Count();
|
||||
$publishedOnCount = $this->getRelatedPages()->count();
|
||||
$publishedOnValue = "$publishedOnCount pages";
|
||||
if ($publishedOnCount == 1) {
|
||||
$publishedOnValue = "$publishedOnCount page";
|
||||
|
@ -1217,26 +1114,49 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
CompositeField::create(
|
||||
CompositeField::create(
|
||||
new ReadonlyField("ID", "ID number". ':', $this->ID),
|
||||
new ReadonlyField("FileType", _t('AssetTableField.TYPE', 'File type') . ':', self::get_file_type($extension)),
|
||||
new ReadonlyField("Size", _t('AssetTableField.SIZE', 'File size') . ':', $this->getFileSizeFormatted()),
|
||||
$urlField = new ReadonlyField('ClickableURL', _t('AssetTableField.URL', 'URL'),
|
||||
sprintf('<a href="%s" target="_blank" class="file-url">%s</a>', $this->getLink(), $this->getLink())
|
||||
new ReadonlyField(
|
||||
"FileType",
|
||||
_t('AssetTableField.TYPE', 'File type') . ':',
|
||||
self::get_file_type($extension)
|
||||
),
|
||||
new ReadonlyField(
|
||||
"Size",
|
||||
_t('AssetTableField.SIZE', 'File size') . ':',
|
||||
$this->getFileSizeFormatted()
|
||||
),
|
||||
$urlField = new ReadonlyField(
|
||||
'ClickableURL',
|
||||
_t('AssetTableField.URL', 'URL'),
|
||||
sprintf(
|
||||
'<a href="%s" target="_blank" class="file-url">%s</a>',
|
||||
$this->getLink(),
|
||||
$this->getLink()
|
||||
)
|
||||
),
|
||||
new ReadonlyField("FilenameWithoutIDField", "Filename". ':', $this->getFilenameWithoutID()),
|
||||
new DateField_Disabled("Created", _t('AssetTableField.CREATED', 'First uploaded') . ':', $this->Created),
|
||||
new DateField_Disabled("LastEdited", _t('AssetTableField.LASTEDIT', 'Last changed') . ':', $this->LastEdited),
|
||||
new DateField_Disabled("LastChanged", _t('AssetTableField.LASTCHANGED', 'Last replaced') . ':', $this->LastChanged),
|
||||
new DateField_Disabled(
|
||||
"Created",
|
||||
_t('AssetTableField.CREATED', 'First uploaded') . ':',
|
||||
$this->Created
|
||||
),
|
||||
new DateField_Disabled(
|
||||
"LastEdited",
|
||||
_t('AssetTableField.LASTEDIT', 'Last changed') . ':',
|
||||
$this->LastEdited
|
||||
),
|
||||
new ReadonlyField("PublishedOn", "Published on". ':', $publishedOnValue),
|
||||
new ReadonlyField("ReferencedOn", "Referenced on". ':', $relationListCountValue),
|
||||
new ReadonlyField("ViewCount", "View count". ':', $this->ViewCount)
|
||||
)
|
||||
)->setName('FilePreviewDataFields')
|
||||
)->setName("FilePreviewData")->addExtraClass('cms-file-info-data')
|
||||
)->setName("FilePreview")->addExtraClass('cms-file-info')
|
||||
);
|
||||
|
||||
$fields->setName('FileP');
|
||||
$fields->addExtraClass('dmsdocument-documentdetails');
|
||||
$urlField->dontEscape = true;
|
||||
|
||||
$this->extend('updateFieldsForFile', $fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
@ -1246,7 +1166,7 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
*
|
||||
* @param File $file
|
||||
*
|
||||
* @return DMSDocument
|
||||
* @return $this
|
||||
*/
|
||||
public function ingestFile($file)
|
||||
{
|
||||
|
@ -1255,162 +1175,192 @@ class DMSDocument extends DataObject implements DMSDocumentInterface
|
|||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package dms
|
||||
*/
|
||||
class DMSDocument_Controller extends Controller
|
||||
{
|
||||
|
||||
public static $testMode = false; //mode to switch for testing. Does not return document download, just document URL
|
||||
|
||||
private static $allowed_actions = array(
|
||||
'index'
|
||||
);
|
||||
|
||||
public function init()
|
||||
/**
|
||||
* Get a data list of documents related to this document
|
||||
*
|
||||
* @return DataList
|
||||
*/
|
||||
public function getRelatedDocuments()
|
||||
{
|
||||
Versioned::choose_site_stage();
|
||||
parent::init();
|
||||
$documents = $this->RelatedDocuments();
|
||||
|
||||
$this->extend('updateRelatedDocuments', $documents);
|
||||
|
||||
return $documents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the document object from the request object's ID parameter.
|
||||
* Returns null, if no document found
|
||||
* @return DMSDocument|null
|
||||
* Get a list of related pages for this document by going through the associated document sets
|
||||
*
|
||||
* @return ArrayList
|
||||
*/
|
||||
protected function getDocumentFromID($request)
|
||||
public function getRelatedPages()
|
||||
{
|
||||
$doc = null;
|
||||
$pages = ArrayList::create();
|
||||
|
||||
$id = Convert::raw2sql($request->param('ID'));
|
||||
|
||||
if (strpos($id, 'version') === 0) { //versioned document
|
||||
$id = str_replace('version', '', $id);
|
||||
$doc = DataObject::get_by_id('DMSDocument_versions', $id);
|
||||
$this->extend('updateVersionFromID', $doc, $request);
|
||||
} else { //normal document
|
||||
$doc = DataObject::get_by_id('DMSDocument', $id);
|
||||
$this->extend('updateDocumentFromID', $doc, $request);
|
||||
foreach ($this->Sets() as $documentSet) {
|
||||
/** @var DocumentSet $documentSet */
|
||||
$pages->add($documentSet->Page());
|
||||
}
|
||||
$pages->removeDuplicates();
|
||||
|
||||
return $doc;
|
||||
$this->extend('updateRelatedPages', $pages);
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the file download without redirecting user, so we can block direct
|
||||
* access to documents.
|
||||
* Get a GridField for managing related documents
|
||||
*
|
||||
* @return GridField
|
||||
*/
|
||||
public function index(SS_HTTPRequest $request)
|
||||
protected function getRelatedDocumentsGridField()
|
||||
{
|
||||
$doc = $this->getDocumentFromID($request);
|
||||
$gridField = GridField::create(
|
||||
'RelatedDocuments',
|
||||
_t('DMSDocument.RELATEDDOCUMENTS', 'Related Documents'),
|
||||
$this->RelatedDocuments(),
|
||||
new GridFieldConfig_RelationEditor
|
||||
);
|
||||
|
||||
if (!empty($doc)) {
|
||||
$canView = false;
|
||||
$gridFieldConfig = $gridField->getConfig();
|
||||
$gridFieldConfig->removeComponentsByType('GridFieldEditButton');
|
||||
$gridFieldConfig->addComponent(new DMSGridFieldEditButton(), 'GridFieldDeleteAction');
|
||||
|
||||
// Runs through all pages that this page links to and sets canView
|
||||
// to true if the user can view ONE of these pages
|
||||
if (method_exists($doc, 'Pages')) {
|
||||
$pages = $doc->Pages();
|
||||
if ($pages->Count() > 0) {
|
||||
foreach ($pages as $page) {
|
||||
if ($page->CanView()) {
|
||||
// just one canView is enough to know that we can
|
||||
// view the file
|
||||
$canView = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if the document isn't on any page, then allow viewing of
|
||||
// the document (because there is no canView() to consult)
|
||||
$canView = true;
|
||||
}
|
||||
}
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldAddNewButton');
|
||||
// Move the autocompleter to the left
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldAddExistingAutocompleter');
|
||||
$gridField->getConfig()->addComponent(
|
||||
$addExisting = new GridFieldAddExistingAutocompleter('buttons-before-left')
|
||||
);
|
||||
|
||||
// check for embargo or expiry
|
||||
if ($doc->isHidden()) {
|
||||
$canView = false;
|
||||
}
|
||||
// Ensure that current document doesn't get returned in the autocompleter
|
||||
$addExisting->setSearchList($this->getRelatedDocumentsForAutocompleter());
|
||||
|
||||
//admins can always download any document, even if otherwise hidden
|
||||
$member = Member::currentUser();
|
||||
if ($member && Permission::checkMember($member, 'ADMIN')) {
|
||||
$canView = true;
|
||||
}
|
||||
// Restrict search fields to specific fields only
|
||||
$addExisting->setSearchFields(array('Title:PartialMatch', 'Filename:PartialMatch'));
|
||||
$addExisting->setResultsFormat('$Filename');
|
||||
|
||||
if ($canView) {
|
||||
$path = $doc->getFullPath();
|
||||
if (is_file($path)) {
|
||||
$fileBin = trim(`whereis file`);
|
||||
if (function_exists('finfo_file')) {
|
||||
// discover the mime type properly
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
$mime = finfo_file($finfo, $path);
|
||||
} elseif (is_executable($fileBin)) {
|
||||
// try to use the system tool
|
||||
$mime = `$fileBin -i -b $path`;
|
||||
$mime = explode(';', $mime);
|
||||
$mime = trim($mime[0]);
|
||||
} else {
|
||||
// make do with what we have
|
||||
$ext = $doc->getExtension();
|
||||
if ($ext =='pdf') {
|
||||
$mime = 'application/pdf';
|
||||
} elseif ($ext == 'html' || $ext =='htm') {
|
||||
$mime = 'text/html';
|
||||
} else {
|
||||
$mime = 'application/octet-stream';
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$testMode) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
// set fallback if no config nor file-specific value
|
||||
$disposition = 'attachment';
|
||||
|
||||
// file-specific setting
|
||||
if ($doc->DownloadBehavior == 'open') {
|
||||
$disposition = 'inline';
|
||||
}
|
||||
|
||||
//if a DMSDocument can be downloaded and all the permissions/privileges has passed,
|
||||
//its ViewCount should be increased by 1 just before the browser sending the file to front.
|
||||
$doc->trackView();
|
||||
|
||||
$this->sendFile($path, $mime, $doc->getFilenameWithoutID(), $disposition);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$testMode) {
|
||||
return 'This asset does not exist.';
|
||||
}
|
||||
$this->httpError(404, 'This asset does not exist.');
|
||||
$this->extend('updateRelatedDocumentsGridField', $gridField);
|
||||
return $gridField;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path File path
|
||||
* @param string $mime File mime type
|
||||
* @param string $name File name
|
||||
* @param string $disposition Content dispositon
|
||||
* Get the list of documents to show in "related documents". This can be modified via the extension point, for
|
||||
* example if you wanted to exclude embargoed documents or something similar.
|
||||
*
|
||||
* @return DataList
|
||||
*/
|
||||
protected function sendFile($path, $mime, $name, $disposition) {
|
||||
header('Content-Type: ' . $mime);
|
||||
header('Content-Length: ' . filesize($path), null);
|
||||
if (!empty($mime) && $mime != "text/html") {
|
||||
header('Content-Disposition: '.$disposition.'; filename="'.addslashes($name).'"');
|
||||
protected function getRelatedDocumentsForAutocompleter()
|
||||
{
|
||||
$documents = DMSDocument::get()->exclude('ID', $this->ID);
|
||||
$this->extend('updateRelatedDocumentsForAutocompleter', $documents);
|
||||
return $documents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks at least one group is selected if CanViewType || CanEditType == 'OnlyTheseUsers'
|
||||
*
|
||||
* @return ValidationResult
|
||||
*/
|
||||
protected function validate()
|
||||
{
|
||||
$valid = parent::validate();
|
||||
|
||||
if ($this->CanViewType == 'OnlyTheseUsers' && !$this->ViewerGroups()->count()) {
|
||||
$valid->error(
|
||||
_t(
|
||||
'DMSDocument.VALIDATIONERROR_NOVIEWERSELECTED',
|
||||
"Selecting 'Only these people' from a viewers list needs at least one group selected."
|
||||
)
|
||||
);
|
||||
}
|
||||
header('Content-transfer-encoding: 8bit');
|
||||
header('Expires: 0');
|
||||
header('Pragma: cache');
|
||||
header('Cache-Control: private');
|
||||
flush();
|
||||
readfile($path);
|
||||
exit;
|
||||
|
||||
if ($this->CanEditType == 'OnlyTheseUsers' && !$this->EditorGroups()->count()) {
|
||||
$valid->error(
|
||||
_t(
|
||||
'DMSDocument.VALIDATIONERROR_NOEDITORSELECTED',
|
||||
"Selecting 'Only these people' from a editors list needs at least one group selected."
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reason as to why this document cannot be viewed.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPermissionDeniedReason()
|
||||
{
|
||||
$result = '';
|
||||
|
||||
if ($this->CanViewType == 'LoggedInUsers') {
|
||||
$result = _t('DMSDocument.PERMISSIONDENIEDREASON_LOGINREQUIRED', 'Please log in to view this document');
|
||||
}
|
||||
|
||||
if ($this->CanViewType == 'OnlyTheseUsers') {
|
||||
$result = _t(
|
||||
'DMSDocument.PERMISSIONDENIEDREASON_NOTAUTHORISED',
|
||||
'You are not authorised to view this document'
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an "action panel" task
|
||||
*
|
||||
* @param string $panelKey
|
||||
* @param string $title
|
||||
* @return $this
|
||||
*/
|
||||
public function addActionPanelTask($panelKey, $title)
|
||||
{
|
||||
$this->actionTasks[$panelKey] = $title;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a HTML representation of the action tasks for the CMS
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getActionTaskHtml()
|
||||
{
|
||||
$html = '<div class="field dmsdocment-actions">'
|
||||
. '<label class="left">' . _t('DMSDocument.ACTIONS_LABEL', 'Actions') . '</label>'
|
||||
. '<ul>';
|
||||
|
||||
foreach ($this->actionTasks as $panelKey => $title) {
|
||||
$panelKey = Convert::raw2xml($panelKey);
|
||||
$title = Convert::raw2xml($title);
|
||||
|
||||
$html .= '<li class="ss-ui-button dmsdocument-action" data-panel="' . $panelKey . '">'
|
||||
. _t('DMSDocument.ACTION_' . strtoupper($panelKey), $title)
|
||||
. '</li>';
|
||||
}
|
||||
|
||||
$html .= '</ul></div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an "action panel" tasks
|
||||
*
|
||||
* @param string $panelKey
|
||||
* @return $this
|
||||
*/
|
||||
public function removeActionPanelTask($panelKey)
|
||||
{
|
||||
if (array_key_exists($panelKey, $this->actionTasks)) {
|
||||
unset($this->actionTasks[$panelKey]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,419 @@
|
|||
<?php
|
||||
/**
|
||||
* A document set is attached to Pages, and contains many DMSDocuments
|
||||
*
|
||||
* @property Varchar Title
|
||||
* @property Text KeyValuePairs
|
||||
* @property Enum SortBy
|
||||
* @property Enum SortByDirection
|
||||
*/
|
||||
class DMSDocumentSet extends DataObject
|
||||
{
|
||||
private static $db = array(
|
||||
'Title' => 'Varchar(255)',
|
||||
'KeyValuePairs' => 'Text',
|
||||
'SortBy' => "Enum('LastEdited,Created,Title')')",
|
||||
'SortByDirection' => "Enum('DESC,ASC')')",
|
||||
);
|
||||
|
||||
private static $has_one = array(
|
||||
'Page' => 'SiteTree',
|
||||
);
|
||||
|
||||
private static $many_many = array(
|
||||
'Documents' => 'DMSDocument',
|
||||
);
|
||||
|
||||
private static $many_many_extraFields = array(
|
||||
'Documents' => array(
|
||||
// Flag indicating if a document was added directly to a set - in which case it is set - or added
|
||||
// via the query-builder.
|
||||
'ManuallyAdded' => 'Boolean(1)',
|
||||
'DocumentSort' => 'Int'
|
||||
),
|
||||
);
|
||||
|
||||
private static $summary_fields = array(
|
||||
'Title' => 'Title',
|
||||
'Documents.Count' => 'No. Documents'
|
||||
);
|
||||
|
||||
/**
|
||||
* Retrieve a list of the documents in this set. An extension hook is provided before the result is returned.
|
||||
*
|
||||
* You can attach an extension to this event:
|
||||
*
|
||||
* <code>
|
||||
* public function updateDocuments($document)
|
||||
* {
|
||||
* // do something
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @return DataList|null
|
||||
*/
|
||||
public function getDocuments()
|
||||
{
|
||||
$documents = $this->Documents();
|
||||
$this->extend('updateDocuments', $documents);
|
||||
return $documents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the "documents" list into the main tab instead of its own tab, and replace the default "Add Document" button
|
||||
* with a customised button for DMS documents
|
||||
*
|
||||
* @return FieldList
|
||||
*/
|
||||
public function getCMSFields()
|
||||
{
|
||||
// PHP 5.3 only
|
||||
$self = $this;
|
||||
$this->beforeUpdateCMSFields(function (FieldList $fields) use ($self) {
|
||||
$fields->removeFieldsFromTab(
|
||||
'Root.Main',
|
||||
array('KeyValuePairs', 'SortBy', 'SortByDirection')
|
||||
);
|
||||
// Don't put the GridField for documents in until the set has been created
|
||||
if (!$self->isInDB()) {
|
||||
$fields->addFieldToTab(
|
||||
'Root.Main',
|
||||
LiteralField::create(
|
||||
'GridFieldNotice',
|
||||
'<p class="message warning">' . _t(
|
||||
'DMSDocumentSet.GRIDFIELD_NOTICE',
|
||||
'Managing documents will be available once you have created this document set.'
|
||||
) . '</p>'
|
||||
),
|
||||
'Title'
|
||||
);
|
||||
} else {
|
||||
$fields->removeByName('DocumentSetSort');
|
||||
// Document listing
|
||||
$gridFieldConfig = GridFieldConfig::create()
|
||||
->addComponents(
|
||||
new GridFieldButtonRow('before'),
|
||||
new GridFieldToolbarHeader(),
|
||||
new GridFieldFilterHeader(),
|
||||
new GridFieldSortableHeader(),
|
||||
new GridFieldDataColumns(),
|
||||
new DMSGridFieldEditButton(),
|
||||
// Special delete dialog to handle custom behaviour of unlinking and deleting
|
||||
new GridFieldDeleteAction(true),
|
||||
new GridFieldDetailForm()
|
||||
);
|
||||
|
||||
if (class_exists('GridFieldPaginatorWithShowAll')) {
|
||||
$paginatorComponent = new GridFieldPaginatorWithShowAll(15);
|
||||
} else {
|
||||
$paginatorComponent = new GridFieldPaginator(15);
|
||||
}
|
||||
$gridFieldConfig->addComponent($paginatorComponent);
|
||||
|
||||
if (class_exists('GridFieldSortableRows')) {
|
||||
$gridFieldConfig->addComponent(new GridFieldSortableRows('DocumentSort'));
|
||||
} elseif (class_exists('GridFieldOrderableRows')) {
|
||||
$gridFieldConfig->addComponent(new GridFieldOrderableRows('DocumentSort'));
|
||||
}
|
||||
|
||||
// Don't show which page this is if we're already editing within a page context
|
||||
if (Controller::curr() instanceof CMSPageEditController) {
|
||||
$fields->removeByName('PageID');
|
||||
} else {
|
||||
$fields->fieldByName('Root.Main.PageID')->setTitle(_t('DMSDocumentSet.SHOWONPAGE', 'Show on page'));
|
||||
}
|
||||
|
||||
// Don't show which page this is if we're already editing within a page context
|
||||
if (Controller::curr() instanceof CMSPageEditController) {
|
||||
$fields->removeByName('PageID');
|
||||
} else {
|
||||
$fields->fieldByName('Root.Main.PageID')->setTitle(_t('DMSDocumentSet.SHOWONPAGE', 'Show on page'));
|
||||
}
|
||||
|
||||
$gridFieldConfig->getComponentByType('GridFieldDataColumns')
|
||||
->setDisplayFields($self->getDocumentDisplayFields())
|
||||
->setFieldCasting(array('LastEdited' => 'Datetime->Ago'))
|
||||
->setFieldFormatting(
|
||||
array(
|
||||
'FilenameWithoutID' => '<a target=\'_blank\' class=\'file-url\''
|
||||
. ' href=\'$Link\'>$FilenameWithoutID</a>',
|
||||
'ManuallyAdded' => function ($value) {
|
||||
if ($value) {
|
||||
return _t('DMSDocumentSet.MANUAL', 'Manually');
|
||||
}
|
||||
return _t('DMSDocumentSet.QUERYBUILDER', 'Query Builder');
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// Override delete functionality with this class
|
||||
$gridFieldConfig->getComponentByType('GridFieldDetailForm')
|
||||
->setItemRequestClass('DMSGridFieldDetailForm_ItemRequest');
|
||||
$gridField = GridField::create(
|
||||
'Documents',
|
||||
false,
|
||||
$self->Documents(),
|
||||
$gridFieldConfig
|
||||
);
|
||||
$gridField->setModelClass('DMSDocument');
|
||||
$gridField->addExtraClass('documents');
|
||||
|
||||
$gridFieldConfig->addComponent(
|
||||
$addNewButton = new DMSGridFieldAddNewButton('buttons-before-left'),
|
||||
'GridFieldExportButton'
|
||||
);
|
||||
$addNewButton->setDocumentSetId($self->ID);
|
||||
|
||||
$fields->removeByName('Documents');
|
||||
$fields->addFieldsToTab(
|
||||
'Root.Main',
|
||||
array(
|
||||
$gridField,
|
||||
HiddenField::create('DMSShortcodeHandlerKey', false, DMS::inst()->getShortcodeHandlerKey())
|
||||
)
|
||||
);
|
||||
$self->addQueryFields($fields);
|
||||
}
|
||||
});
|
||||
$this->addRequirements();
|
||||
return parent::getCMSFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add required CSS and Javascript requirements for managing documents
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function addRequirements()
|
||||
{
|
||||
// Javascript to customize the grid field for the DMS document (overriding entwine
|
||||
// in FRAMEWORK_DIR.'/javascript/GridField.js'
|
||||
Requirements::javascript(DMS_DIR . '/javascript/DMSGridField.js');
|
||||
Requirements::css(DMS_DIR . '/dist/css/dmsbundle.css');
|
||||
|
||||
// Javascript for the link editor pop-up in TinyMCE
|
||||
Requirements::javascript(DMS_DIR . '/javascript/DocumentHtmlEditorFieldToolbar.js');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the query fields to build the document logic to the DMSDocumentSet.
|
||||
*
|
||||
* @param FieldList $fields
|
||||
*/
|
||||
public function addQueryFields($fields)
|
||||
{
|
||||
/** @var DMSDocument $doc */
|
||||
$doc = singleton('DMSDocument');
|
||||
/** @var FormField $field */
|
||||
$dmsDocFields = $doc->scaffoldSearchFields(array('fieldClasses' => true));
|
||||
$membersMap = Member::get()->map('ID', 'Name')->toArray();
|
||||
asort($membersMap);
|
||||
|
||||
foreach ($dmsDocFields as $field) {
|
||||
if ($field instanceof ListboxField) {
|
||||
$map = ($field->getName() === 'Tags__ID') ? $doc->getAllTagsMap() : $membersMap;
|
||||
$field->setMultiple(true)->setSource($map);
|
||||
|
||||
if ($field->getName() === 'Tags__ID') {
|
||||
$field->setRightTitle(
|
||||
_t(
|
||||
'DMSDocumentSet.TAGS_RIGHT_TITLE',
|
||||
'Tags can be set in the taxonomy area, and can be assigned when editing a document.'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$keyValPairs = DMSJsonField::create('KeyValuePairs', $dmsDocFields->toArray());
|
||||
|
||||
// Now lastly add the sort fields
|
||||
$sortedBy = FieldGroup::create('SortedBy', array(
|
||||
DropdownField::create('SortBy', '', array(
|
||||
'LastEdited' => 'Last changed',
|
||||
'Created' => 'Created',
|
||||
'Title' => 'Document title',
|
||||
), 'LastEdited'),
|
||||
DropdownField::create(
|
||||
'SortByDirection',
|
||||
'',
|
||||
array(
|
||||
'DESC' => _t('DMSDocumentSet.DIRECTION_DESCENDING', 'Descending'),
|
||||
'ASC' => _t('DMSDocumentSet.DIRECTION_ASCENDING', 'Ascending')
|
||||
),
|
||||
'DESC'
|
||||
),
|
||||
));
|
||||
|
||||
$sortedBy->setTitle(_t('DMSDocumentSet.SORTED_BY', 'Sort the document set by:'));
|
||||
$fields->addFieldsToTab(
|
||||
'Root.QueryBuilder',
|
||||
array(
|
||||
LiteralField::create(
|
||||
'GridFieldNotice',
|
||||
'<p class="message warning">' . _t(
|
||||
'DMSDocumentSet.QUERY_BUILDER_NOTICE',
|
||||
'The query builder provides the ability to add documents to a document set based on the ' .
|
||||
'filters below. Please note that the set will be built using this criteria when you save the ' .
|
||||
'form. This set will not be dynamically updated (see the documentation for more information).'
|
||||
) . '</p>'
|
||||
),
|
||||
$keyValPairs,
|
||||
$sortedBy
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function onBeforeWrite()
|
||||
{
|
||||
parent::onBeforeWrite();
|
||||
|
||||
$this->saveLinkedDocuments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of the documents in this set. An extension hook is provided before the result is returned.
|
||||
*/
|
||||
public function saveLinkedDocuments()
|
||||
{
|
||||
if (empty($this->KeyValuePairs) || !$this->isChanged('KeyValuePairs')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$keyValuesPair = Convert::json2array($this->KeyValuePairs);
|
||||
|
||||
/** @var DMSDocument $dmsDoc */
|
||||
$dmsDoc = singleton('DMSDocument');
|
||||
$context = $dmsDoc->getDefaultSearchContext();
|
||||
|
||||
$sortBy = $this->SortBy ? $this->SortBy : 'LastEdited';
|
||||
$sortByDirection = $this->SortByDirection ? $this->SortByDirection : 'DESC';
|
||||
$sortedBy = sprintf('%s %s', $sortBy, $sortByDirection);
|
||||
|
||||
/** @var DataList $documents */
|
||||
$documents = $context->getResults($keyValuesPair, $sortedBy);
|
||||
$documents = $this->addEmbargoConditions($documents);
|
||||
$documents = $this->addQueryBuilderSearchResults($documents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add embargo date conditions to a search query
|
||||
*
|
||||
* @param DataList $documents
|
||||
* @return DataList
|
||||
*/
|
||||
protected function addEmbargoConditions(DataList $documents)
|
||||
{
|
||||
$now = SS_Datetime::now()->Rfc2822();
|
||||
|
||||
return $documents->where(
|
||||
"\"EmbargoedIndefinitely\" = 0 AND "
|
||||
. " \"EmbargoedUntilPublished\" = 0 AND "
|
||||
. "(\"EmbargoedUntilDate\" IS NULL OR "
|
||||
. "(\"EmbargoedUntilDate\" IS NOT NULL AND '{$now}' >= \"EmbargoedUntilDate\")) AND "
|
||||
. "\"ExpireAtDate\" IS NULL OR (\"ExpireAtDate\" IS NOT NULL AND '{$now}' < \"ExpireAtDate\")"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all ManuallyAdded = 0 original results and add in the new documents returned by the search context
|
||||
*
|
||||
* @param DataList $documents
|
||||
* @return DataList
|
||||
*/
|
||||
protected function addQueryBuilderSearchResults(DataList $documents)
|
||||
{
|
||||
/** @var ManyManyList $originals Documents that belong to just this set. */
|
||||
$originals = $this->Documents();
|
||||
$originals->removeByFilter('"ManuallyAdded" = 0');
|
||||
|
||||
foreach ($documents as $document) {
|
||||
$originals->add($document, array('ManuallyAdded' => 0));
|
||||
}
|
||||
|
||||
return $originals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customise the display fields for the documents GridField
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDocumentDisplayFields()
|
||||
{
|
||||
return array_merge(
|
||||
(array) DMSDocument::create()->config()->get('display_fields'),
|
||||
array('ManuallyAdded' => _t('DMSDocumentSet.ADDEDMETHOD', 'Added'))
|
||||
);
|
||||
}
|
||||
|
||||
protected function validate()
|
||||
{
|
||||
$result = parent::validate();
|
||||
|
||||
if (!$this->getTitle()) {
|
||||
$result->error(_t('DMSDocumentSet.VALIDATION_NO_TITLE', '\'Title\' is required.'));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function canView($member = null)
|
||||
{
|
||||
$extended = $this->extendedCan(__FUNCTION__, $member);
|
||||
if ($extended !== null) {
|
||||
return $extended;
|
||||
}
|
||||
return $this->getGlobalPermission($member);
|
||||
}
|
||||
|
||||
public function canCreate($member = null)
|
||||
{
|
||||
$extended = $this->extendedCan(__FUNCTION__, $member);
|
||||
if ($extended !== null) {
|
||||
return $extended;
|
||||
}
|
||||
return $this->getGlobalPermission($member);
|
||||
}
|
||||
|
||||
public function canEdit($member = null)
|
||||
{
|
||||
$extended = $this->extendedCan(__FUNCTION__, $member);
|
||||
if ($extended !== null) {
|
||||
return $extended;
|
||||
}
|
||||
return $this->getGlobalPermission($member);
|
||||
}
|
||||
|
||||
public function canDelete($member = null)
|
||||
{
|
||||
$extended = $this->extendedCan(__FUNCTION__, $member);
|
||||
if ($extended !== null) {
|
||||
return $extended;
|
||||
}
|
||||
return $this->getGlobalPermission($member);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a then given (or logged in) member is either an ADMIN, SITETREE_EDIT_ALL or has access
|
||||
* to the DMSDocumentAdmin module, in which case permissions is granted.
|
||||
*
|
||||
* @param Member $member
|
||||
* @return bool
|
||||
*/
|
||||
public function getGlobalPermission(Member $member = null)
|
||||
{
|
||||
if (!$member || !(is_a($member, 'Member')) || is_numeric($member)) {
|
||||
$member = Member::currentUser();
|
||||
}
|
||||
|
||||
$result = ($member &&
|
||||
Permission::checkMember(
|
||||
$member,
|
||||
array('ADMIN', 'SITETREE_EDIT_ALL', 'CMS_ACCESS_DMSDocumentAdmin')
|
||||
)
|
||||
);
|
||||
|
||||
return (bool) $result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
class DMSDocument_Controller extends Controller
|
||||
{
|
||||
/**
|
||||
* Mode to switch for testing. Does not return document download, just document URL.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public static $testMode = false;
|
||||
|
||||
private static $allowed_actions = array(
|
||||
'index'
|
||||
);
|
||||
|
||||
public function init()
|
||||
{
|
||||
Versioned::choose_site_stage();
|
||||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the document object from the request object's ID parameter.
|
||||
* Returns null, if no document found
|
||||
*
|
||||
* @param SS_HTTPRequest $request
|
||||
* @return DMSDocument|null
|
||||
*/
|
||||
protected function getDocumentFromID($request)
|
||||
{
|
||||
$doc = null;
|
||||
|
||||
$id = Convert::raw2sql($request->param('ID'));
|
||||
if (strpos($id, 'version') === 0) {
|
||||
// Versioned document
|
||||
$id = $this->getDocumentIdFromSlug(str_replace('version', '', $id));
|
||||
$doc = DataObject::get_by_id('DMSDocument_versions', $id);
|
||||
$this->extend('updateVersionFromID', $doc, $request);
|
||||
} else {
|
||||
// Normal document
|
||||
$doc = DataObject::get_by_id('DMSDocument', $this->getDocumentIdFromSlug($id));
|
||||
$this->extend('updateDocumentFromID', $doc, $request);
|
||||
}
|
||||
|
||||
return $doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a document's ID from a "friendly" URL slug containing a numeric ID and slugged title
|
||||
*
|
||||
* @param string $slug
|
||||
* @return int
|
||||
* @throws InvalidArgumentException if an invalid format is provided
|
||||
*/
|
||||
protected function getDocumentIdFromSlug($slug)
|
||||
{
|
||||
$parts = (array) sscanf($slug, '%d-%s');
|
||||
$id = array_shift($parts);
|
||||
if (is_numeric($id)) {
|
||||
return (int) $id;
|
||||
}
|
||||
throw new InvalidArgumentException($slug . ' is not a valid DMSDocument URL');
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the file download without redirecting user, so we can block direct
|
||||
* access to documents.
|
||||
*/
|
||||
public function index(SS_HTTPRequest $request)
|
||||
{
|
||||
$doc = $this->getDocumentFromID($request);
|
||||
|
||||
if (!empty($doc)) {
|
||||
$canView = $doc->canView();
|
||||
|
||||
if ($canView) {
|
||||
$path = $doc->getFullPath();
|
||||
if (is_file($path)) {
|
||||
$fileBin = trim(`whereis file`);
|
||||
if (function_exists('finfo_file')) {
|
||||
// discover the mime type properly
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
$mime = finfo_file($finfo, $path);
|
||||
} elseif (is_executable($fileBin)) {
|
||||
$path = escapeshellarg($path);
|
||||
// try to use the system tool
|
||||
$mime = `$fileBin -i -b $path`;
|
||||
$mime = explode(';', $mime);
|
||||
$mime = trim($mime[0]);
|
||||
} else {
|
||||
// make do with what we have
|
||||
$ext = $doc->getExtension();
|
||||
if ($ext == 'pdf') {
|
||||
$mime = 'application/pdf';
|
||||
} elseif ($ext == 'html' || $ext =='htm') {
|
||||
$mime = 'text/html';
|
||||
} else {
|
||||
$mime = 'application/octet-stream';
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$testMode) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
// set fallback if no config nor file-specific value
|
||||
$disposition = 'attachment';
|
||||
|
||||
// file-specific setting
|
||||
if ($doc->DownloadBehavior == 'open') {
|
||||
$disposition = 'inline';
|
||||
}
|
||||
|
||||
//if a DMSDocument can be downloaded and all the permissions/privileges has passed,
|
||||
//its ViewCount should be increased by 1 just before the browser sending the file to front.
|
||||
$doc->trackView();
|
||||
|
||||
return $this->sendFile($path, $mime, $doc->getFilenameWithoutID(), $disposition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$testMode) {
|
||||
return 'This asset does not exist.';
|
||||
}
|
||||
$this->httpError(404, 'This asset does not exist.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path File path
|
||||
* @param string $mime File mime type
|
||||
* @param string $name File name
|
||||
* @param string $disposition Content dispositon
|
||||
*/
|
||||
protected function sendFile($path, $mime, $name, $disposition)
|
||||
{
|
||||
header('Content-Type: ' . $mime);
|
||||
header('Content-Length: ' . filesize($path), null);
|
||||
if (!empty($mime) && $mime != "text/html") {
|
||||
header('Content-Disposition: '.$disposition.'; filename="'.addslashes($name).'"');
|
||||
}
|
||||
header('Content-transfer-encoding: 8bit');
|
||||
header('Expires: 0');
|
||||
header('Pragma: cache');
|
||||
header('Cache-Control: private');
|
||||
flush();
|
||||
readfile($path);
|
||||
exit;
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ class DMSDocument_versions extends DataObject
|
|||
private static $display_fields = array(
|
||||
'VersionCounter' => 'Version Counter',
|
||||
'FilenameWithoutID' => 'Filename',
|
||||
'LastChanged' => 'Last Changed'
|
||||
'LastEdited' => 'Last Changed'
|
||||
);
|
||||
|
||||
private static $summary_fields = array(
|
||||
|
@ -47,7 +47,7 @@ class DMSDocument_versions extends DataObject
|
|||
);
|
||||
|
||||
private static $default_sort = array(
|
||||
'LastChanged' => 'DESC'
|
||||
'LastEdited' => 'DESC'
|
||||
);
|
||||
|
||||
|
||||
|
@ -179,7 +179,7 @@ class DMSDocument_versions extends DataObject
|
|||
if (!$filename) {
|
||||
$filename = $this->Filename;
|
||||
}
|
||||
return DMS::get_dms_path() . DIRECTORY_SEPARATOR . $this->Folder . DIRECTORY_SEPARATOR . $filename;
|
||||
return DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . $this->Folder . DIRECTORY_SEPARATOR . $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,14 +206,17 @@ class DMSDocument_versions extends DataObject
|
|||
$filename = $doc->Filename;
|
||||
|
||||
do {
|
||||
$versionPaddingString = str_pad($versionCounter, 4, '0', STR_PAD_LEFT); //add leading zeros to make sorting accurate up to 10,000 documents
|
||||
// Add leading zeros to make sorting accurate up to 10,000 documents
|
||||
$versionPaddingString = str_pad($versionCounter, 4, '0', STR_PAD_LEFT);
|
||||
$newVersionFilename = preg_replace('/([0-9]+~)(.*?)/', '$1~'.$versionPaddingString.'~$2', $filename);
|
||||
|
||||
if ($newVersionFilename == $filename || empty($newVersionFilename)) { //sanity check for crazy document names
|
||||
// Sanity check for crazy document names
|
||||
if ($newVersionFilename == $filename || empty($newVersionFilename)) {
|
||||
user_error('Cannot generate new document filename for file: '.$filename, E_USER_ERROR);
|
||||
}
|
||||
|
||||
$versionCounter++; //increase the counter for the next loop run, if necessary
|
||||
// Increase the counter for the next loop run, if necessary
|
||||
$versionCounter++;
|
||||
} while (file_exists($this->getFullPath($newVersionFilename)));
|
||||
|
||||
return $newVersionFilename;
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Hold a set of metadata category/value tags associated with a DMSDocument
|
||||
*
|
||||
* @package dms
|
||||
*/
|
||||
class DMSTag extends DataObject
|
||||
{
|
||||
|
||||
private static $db = array(
|
||||
'Category' => 'Varchar(1024)',
|
||||
'Value' => 'Varchar(1024)',
|
||||
'MultiValue' => 'Boolean(1)'
|
||||
);
|
||||
|
||||
private static $belongs_many_many = array(
|
||||
'Documents' => 'DMSDocument'
|
||||
);
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
<?php
|
||||
/**
|
||||
* This build task helps to migrate DMS data structures from DMS 1.x to 2.x which introduces document sets.
|
||||
*
|
||||
* See the "document-sets.md" migration guide for more information and use examples.
|
||||
*/
|
||||
class MigrateToDocumentSetsTask extends BuildTask
|
||||
{
|
||||
protected $title = 'DMS 2.0 Migration Tool';
|
||||
|
||||
protected $description = 'Migration tool for upgrading from DMS 1.x to 2.x. Add "action=create-default-document-set" to create a default set. "reassign-documents" to reassign legacy document relations. "dryrun=1" to show changes without writing.';
|
||||
|
||||
/**
|
||||
* The valid actions that this task can perform (and the method that does them as the key)
|
||||
* @var array
|
||||
*/
|
||||
protected $validActions = array(
|
||||
'createDefaultSet' => 'create-default-document-set',
|
||||
'reassignDocuments' => 'reassign-documents'
|
||||
);
|
||||
|
||||
/**
|
||||
* @var SS_HTTPRequest
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Holds number of pages/sets/documents processed for output at the end. Example:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'total-pages' => 0,
|
||||
* 'pages-updated' => 0
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* The individual action methods will update these metrics as required
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $results = array();
|
||||
|
||||
public function run($request)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
$action = $request->getVar('action');
|
||||
if (!in_array($action, $this->validActions)) {
|
||||
$this->output(
|
||||
'Error! Specified action is not valid. Valid actions are: ' . implode(', ', $this->validActions)
|
||||
);
|
||||
$this->output('You can add "dryrun=1" to enable dryrun mode where no changes will be written to the DB.');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->outputHeader();
|
||||
$action = array_search($action, $this->validActions);
|
||||
$this->$action();
|
||||
$this->outputResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether dryrun mode is enabled ("dryrun=1")
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isDryrun()
|
||||
{
|
||||
return (bool) $this->request->getVar('dryrun') == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a default document set for any valid page that doesn't have one
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function createDefaultSet()
|
||||
{
|
||||
$pages = SiteTree::get();
|
||||
foreach ($pages as $page) {
|
||||
// Only handle valid page types
|
||||
if (!$page->config()->get('documents_enabled')) {
|
||||
$this->addResult('Skipped: documents disabled');
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($page->DocumentSets()->count()) {
|
||||
// Don't add a set if it already has one
|
||||
$this->addResult('Skipped: already has a set');
|
||||
continue;
|
||||
}
|
||||
$this->addDefaultDocumentSet($page);
|
||||
$this->addResult('Default document set added');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reassign documents to the default document set, where they'd previously have been assigned to pages
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function reassignDocuments()
|
||||
{
|
||||
$countCheck = SQLSelect::create('*', 'DMSDocument_Pages');
|
||||
if (!$countCheck->count()) {
|
||||
$this->output('There was no data to migrate. Finishing.');
|
||||
return $this;
|
||||
}
|
||||
|
||||
$query = SQLSelect::create(array('DMSDocumentID', 'SiteTreeID'), 'DMSDocument_Pages');
|
||||
$result = $query->execute();
|
||||
|
||||
foreach ($result as $row) {
|
||||
$document = DMSDocument::get()->byId($row['DMSDocumentID']);
|
||||
if (!$document) {
|
||||
$this->addResult('Skipped: document does not exist');
|
||||
continue;
|
||||
}
|
||||
|
||||
$page = SiteTree::get()->byId($row['SiteTreeID']);
|
||||
if (!$page) {
|
||||
$this->addResult('Skipped: page does not exist');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't try and process pages that don't have a document set. This should be created by the first
|
||||
// action step in this build task, so shouldn't occur if run in correct order.
|
||||
if (!$page->DocumentSets()->count()) {
|
||||
$this->addResult('Skipped: no default document set');
|
||||
continue;
|
||||
}
|
||||
$this->addDocumentToSet($document, $page->DocumentSets()->first());
|
||||
$this->addResult('Reassigned to document set');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a "default" document set and add it to the given Page via the ORM relationship added by
|
||||
* {@link DMSSiteTreeExtension}
|
||||
*
|
||||
* @param SiteTree $page
|
||||
* @return $this
|
||||
*/
|
||||
protected function addDefaultDocumentSet(SiteTree $page)
|
||||
{
|
||||
if ($this->isDryrun()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$set = DMSDocumentSet::create();
|
||||
$set->Title = 'Default';
|
||||
$set->write();
|
||||
|
||||
$page->DocumentSets()->add($set);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given document to the given document set
|
||||
*
|
||||
* @param DMSDocument $document
|
||||
* @param DMSDocumentSet $set
|
||||
* @return $this
|
||||
*/
|
||||
protected function addDocumentToSet(DMSDocument $document, DMSDocumentSet $set)
|
||||
{
|
||||
if ($this->isDryrun()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$set->Documents()->add($document);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a header info line
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function outputHeader()
|
||||
{
|
||||
$this->output('Migrating DMS data to 2.x for document sets');
|
||||
if ($this->isDryrun()) {
|
||||
$this->output('NOTE: Dryrun mode enabled. No changes will be written.');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a "finished" notice and the results of what was done
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function outputResults()
|
||||
{
|
||||
$this->output();
|
||||
$this->output('Finished:');
|
||||
foreach ($this->results as $metric => $count) {
|
||||
$this->output('+ ' . $metric . ': ' . $count);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the $increment to the result key identified by $key
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $increment
|
||||
* @return $this
|
||||
*/
|
||||
protected function addResult($key, $increment = 1)
|
||||
{
|
||||
if (!array_key_exists($key, $this->results)) {
|
||||
$this->results[$key] = 0;
|
||||
}
|
||||
$this->results[$key] += $increment;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a message formatted either for CLI or browser output
|
||||
*
|
||||
* @param string $message
|
||||
* @return $this
|
||||
*/
|
||||
public function output($message = '')
|
||||
{
|
||||
if ($this->isCli()) {
|
||||
echo $message, PHP_EOL;
|
||||
} else {
|
||||
echo $message . '<br />';
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the task is called via CLI or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isCli()
|
||||
{
|
||||
return Director::is_cli();
|
||||
}
|
||||
}
|
|
@ -39,19 +39,22 @@ class ShortCodeRelationFinder
|
|||
}
|
||||
|
||||
/**
|
||||
* @param int $number
|
||||
* @return DataList
|
||||
*/
|
||||
public function getList($number)
|
||||
{
|
||||
$number = (int) $number;
|
||||
$list = DataList::create('SiteTree');
|
||||
$where = array();
|
||||
$fields = $this->getShortCodeFields('SiteTree');
|
||||
$shortcode = DMS::inst()->getShortcodeHandlerKey();
|
||||
foreach ($fields as $ancClass => $ancFields) {
|
||||
foreach ($ancFields as $ancFieldName => $ancFieldSpec) {
|
||||
if ($ancClass != "SiteTree") {
|
||||
$list = $list->leftJoin($ancClass, '"'.$ancClass.'"."ID" = "SiteTree"."ID"');
|
||||
}
|
||||
$where[] = "\"$ancClass\".\"$ancFieldName\" LIKE '%[dms_document_link,id=$number]%'"; //."%s" LIKE ""',
|
||||
$where[] = "\"$ancClass\".\"$ancFieldName\" LIKE '%[{$shortcode},id=$number]%'"; //."%s" LIKE ""',
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,13 +9,18 @@
|
|||
"email": "julian@silverstripe.com"
|
||||
}],
|
||||
"require": {
|
||||
"silverstripe/framework": "~3.1",
|
||||
"silverstripe/cms": "~3.1",
|
||||
"silverstripe-australia/gridfieldextensions": "^1.1.0"
|
||||
"silverstripe/framework": "^3.5",
|
||||
"silverstripe/cms": "^3.5",
|
||||
"symbiote/silverstripe-gridfieldextensions": "^2.0",
|
||||
"silverstripe/taxonomy": "^1.2",
|
||||
"mustangostang/spyc": "<=0.6.2"
|
||||
},
|
||||
"suggest": {
|
||||
"undefinedoffset/sortablegridfield": "Allow documents to be reordered via drag-and-drop"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
"dev-master": "2.4.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
20
config.rb
|
@ -1,20 +0,0 @@
|
|||
# Require any additional compass plugins here.
|
||||
require 'compass-colors'
|
||||
|
||||
project_type = :stand_alone
|
||||
# Set this to the root of your project when deployed:
|
||||
http_path = "/"
|
||||
css_dir = "css"
|
||||
sass_dir = "scss"
|
||||
images_dir = "images"
|
||||
javascripts_dir = "javascript"
|
||||
output_style = :compact
|
||||
|
||||
# To enable relative paths to assets via compass helper functions. Uncomment:
|
||||
relative_assets = true
|
||||
|
||||
# disable comments in the output. We want admin comments
|
||||
# to be verbose
|
||||
line_comments = false
|
||||
|
||||
asset_cache_buster :none
|
|
@ -1,62 +0,0 @@
|
|||
form.small .field input.text, form.small .field textarea, form.small .field select, form.small .field .TreeDropdownField, .field.small input.text, .field.small textarea, .field.small select, .field.small .TreeDropdownField { width: 100%; }
|
||||
|
||||
#FileP .fieldgroup-field { width: 100%; }
|
||||
#FileP .fieldgroup-field .cms-file-info-preview { box-shadow: none; }
|
||||
#FileP .fieldgroup-field .cms-file-info-data { width: 400px; }
|
||||
#FileP .fieldgroup-field .fieldholder-small { margin-top: 5px; }
|
||||
#FileP .fieldgroup-field .fieldholder-small label { width: auto; margin-left: 0; padding-top: 0; margin-right: 10px; font-weight: bold; float: left; }
|
||||
#FileP .fieldgroup-field .fieldholder-small .readonly { font-style: italic; color: #666; }
|
||||
|
||||
#DocumentTypeID .middleColumn { overflow: auto; min-width: 800px; }
|
||||
#DocumentTypeID .middleColumn ul { padding: 0; }
|
||||
#DocumentTypeID .middleColumn ul input[type="radio"] { display: none; }
|
||||
#DocumentTypeID .middleColumn ul li { display: table; padding: 0; width: 125px; height: 40px; white-space: normal; margin-right: -1px; border-radius: 0; }
|
||||
#DocumentTypeID .middleColumn ul li:first-child { border-radius: 6px 0 0 6px; border-left: 1px solid #C0C0C2; }
|
||||
#DocumentTypeID .middleColumn ul li:last-child { border-radius: 0 6px 6px 0; }
|
||||
#DocumentTypeID .middleColumn ul li.selected, .ie8 #DocumentTypeID .middleColumn ul li.selected { border-bottom: 1px solid #C0C0C2; background: -moz-linear-gradient(#c0c0c0, #e6e6e6); background: -webkit-linear-gradient(#c0c0c0, #e6e6e6); background: linear-gradient(#c0c0c0, #e6e6e6); background-color: silver; filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6'); /* IE6 & IE7 */ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6')"; /* IE8 */ box-shadow: 0 1px 1px 0 #A0A0A0 inset; }
|
||||
#DocumentTypeID .middleColumn ul li.selected :after, .ie8 #DocumentTypeID .middleColumn ul li.selected :after { box-shadow: 0 1px 1px 0 #DDD; }
|
||||
#DocumentTypeID .middleColumn ul li label { display: table-cell; vertical-align: middle; text-align: center; padding: 0 10px; }
|
||||
|
||||
#Actions { box-shadow: none; border: none; padding: 0; }
|
||||
#Actions li { margin-left: 2px; }
|
||||
#Actions li:first-child { margin-left: 0; }
|
||||
#Actions li.delete-button-appended { display: inline-block; position: relative; margin-left: 0; }
|
||||
#Actions li.dms-active { border-bottom: 1px solid #C0C0C2; background: -moz-linear-gradient(#c0c0c0, #e6e6e6); background: -webkit-linear-gradient(#c0c0c0, #e6e6e6); background: linear-gradient(#c0c0c0, #e6e6e6); background-color: silver; filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6'); /* IE6 & IE7 */ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6')"; /* IE8 */ box-shadow: 0 1px 1px 0 #A0A0A0 inset; }
|
||||
#Actions li.dms-active:after { content: ''; display: block; position: absolute; top: 33px; left: 50%; margin-left: -6px; width: 12px; height: 12px; background: #F8F8F8; border-right: 1px solid #B3B3B3; border-top: 1px solid #B3B3B3; -moz-transform: rotate(-45deg); -webkit-transform: rotate(-45deg); pointer-events: none; z-index: 10; }
|
||||
|
||||
.DMSDocumentActionsPanel { /*.middleColumn{
|
||||
margin-left:184px;
|
||||
width: 510px;
|
||||
form.small &{
|
||||
margin-left: 120px;
|
||||
}
|
||||
}
|
||||
*/ /*label.fieldholder-small-label{
|
||||
display: none;
|
||||
}*/ }
|
||||
.DMSDocumentActionsPanel .fieldgroup { display: none; float: none; width: auto; background: #f8f8f8; padding: 15px; border: 1px solid #d0d3d5; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .fieldholder-small label { float: none; width: auto; margin: 0; padding: 0; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .fieldholder-small label.ss-ui-button { float: left; margin: 0 10px 0 0; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .embargo li, .DMSDocumentActionsPanel .fieldgroup .expiry li { float: none; width: 100%; margin-left: 8px; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .embargo li label, .DMSDocumentActionsPanel .fieldgroup .expiry li label { padding-left: 10px; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .embargo .embargoDatetime, .DMSDocumentActionsPanel .fieldgroup .embargo .expiryDatetime, .DMSDocumentActionsPanel .fieldgroup .expiry .embargoDatetime, .DMSDocumentActionsPanel .fieldgroup .expiry .expiryDatetime { margin-top: 0; margin-left: 34px; overflow: hidden; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .embargo .embargoDatetime .field.date, .DMSDocumentActionsPanel .fieldgroup .embargo .embargoDatetime .field.time, .DMSDocumentActionsPanel .fieldgroup .embargo .expiryDatetime .field.date, .DMSDocumentActionsPanel .fieldgroup .embargo .expiryDatetime .field.time, .DMSDocumentActionsPanel .fieldgroup .expiry .embargoDatetime .field.date, .DMSDocumentActionsPanel .fieldgroup .expiry .embargoDatetime .field.time, .DMSDocumentActionsPanel .fieldgroup .expiry .expiryDatetime .field.date, .DMSDocumentActionsPanel .fieldgroup .expiry .expiryDatetime .field.time { display: inline-block; width: auto; margin: 0; padding: 0; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .embargo .embargoDatetime .field.date .middleColumn, .DMSDocumentActionsPanel .fieldgroup .embargo .expiryDatetime .field.date .middleColumn, .DMSDocumentActionsPanel .fieldgroup .expiry .embargoDatetime .field.date .middleColumn, .DMSDocumentActionsPanel .fieldgroup .expiry .expiryDatetime .field.date .middleColumn { background: url("../images/calendar-month.png") 90px 7px no-repeat; overflow: hidden; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .embargo .embargoDatetime .field.time .middleColumn, .DMSDocumentActionsPanel .fieldgroup .embargo .expiryDatetime .field.time .middleColumn, .DMSDocumentActionsPanel .fieldgroup .expiry .embargoDatetime .field.time .middleColumn, .DMSDocumentActionsPanel .fieldgroup .expiry .expiryDatetime .field.time .middleColumn { background: url("../images/clock-frame.png") 90px 7px no-repeat; overflow: hidden; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .embargo .embargoDatetime .middleColumn, .DMSDocumentActionsPanel .fieldgroup .embargo .expiryDatetime .middleColumn, .DMSDocumentActionsPanel .fieldgroup .expiry .embargoDatetime .middleColumn, .DMSDocumentActionsPanel .fieldgroup .expiry .expiryDatetime .middleColumn { margin-left: 0; width: auto; border: none; }
|
||||
.DMSDocumentActionsPanel .fieldgroup .embargo .embargoDatetime .middleColumn input, .DMSDocumentActionsPanel .fieldgroup .embargo .expiryDatetime .middleColumn input, .DMSDocumentActionsPanel .fieldgroup .expiry .embargoDatetime .middleColumn input, .DMSDocumentActionsPanel .fieldgroup .expiry .expiryDatetime .middleColumn input { width: 80px; margin-right: 40px; }
|
||||
.DMSDocumentActionsPanel #Embargo { border: none; box-shadow: none; -moz-box-shadow: none; -webkit-box-shadow: none; }
|
||||
.DMSDocumentActionsPanel .ss-uploadfield-files .ss-uploadfield-item-preview { background: url("../images/app_icons/generic_32.png") -10px -6px no-repeat; }
|
||||
.DMSDocumentActionsPanel .ss-uploadfield-files .ss-uploadfield-item-name span.name { width: 260px; }
|
||||
.DMSDocumentActionsPanel .ss-uploadfield-files .ss-uploadfield-item-actions .ss-uploadfield-item-cancel { width: auto; text-indent: 0; }
|
||||
.DMSDocumentActionsPanel .ss-uploadfield-files .ss-uploadfield-item-actions .ss-uploadfield-item-cancel .btn-icon-deleteLight { background-position: 0 -128px; display: inline-block; }
|
||||
.DMSDocumentActionsPanel .ss-uploadfield-files .ss-uploadfield-item-actions .ss-uploadfield-item-cancel .ui-button-text { display: block; position: relative; float: right; color: #555; padding: 0; padding-left: 2em; }
|
||||
.DMSDocumentActionsPanel > .fieldgroup.middleColumn { overflow: hidden; display: block; }
|
||||
.DMSDocumentActionsPanel > .fieldgroup.middleColumn .fieldgroup-field { width: 100%; }
|
||||
|
||||
#Form_ItemEditForm fieldset table.ss-gridfield-table { width: 494px; }
|
||||
#Form_ItemEditForm fieldset table.ss-gridfield-table tr th.main { min-width: 175px; }
|
||||
#Form_ItemEditForm fieldset table.ss-gridfield-table tr th.main.col-action_SetOrderID { width: 60px; min-width: 60px; }
|
||||
#Form_ItemEditForm fieldset table.ss-gridfield-table tr td { white-space: normal; }
|
||||
|
||||
#ui-datepicker-div { border: 1px solid #DDD; }
|
|
@ -1,70 +0,0 @@
|
|||
.ui-autocomplete { border: 1px solid #DDD; box-shadow: 0 1px 2px 0px #AFAFAF; max-height: 300px; overflow: scroll; }
|
||||
|
||||
.cms fieldset.documents table td, .cms fieldset.relatedLinks table td { white-space: normal; }
|
||||
.cms fieldset.documents table td.col-buttons, .cms fieldset.relatedLinks table td.col-buttons { white-space: nowrap; }
|
||||
.cms fieldset.documents table td.col-buttons .dms-delete-link-only .ui-icon, .cms fieldset.relatedLinks table td.col-buttons .dms-delete-link-only .ui-icon { background: url(../images/chain-unchain.png) no-repeat; }
|
||||
.cms fieldset.documents table tr.dms-document-hidden-row.odd, .cms fieldset.relatedLinks table tr.dms-document-hidden-row.odd { background-color: rgba(241, 220, 222, 0.6); }
|
||||
.cms fieldset.documents table tr.dms-document-hidden-row.even, .cms fieldset.relatedLinks table tr.dms-document-hidden-row.even { background-color: rgba(242, 201, 203, 0.675); }
|
||||
.cms fieldset.documents table tr.dms-document-hidden-row:hover, .cms fieldset.relatedLinks table tr.dms-document-hidden-row:hover { background-color: rgba(244, 171, 172, 0.8) !important; }
|
||||
|
||||
.DMSDocumentAddController .ui-tabs ul.ui-tabs-nav { border-bottom: none; float: right; margin: 8px 0 -1px 0; padding: 0 24px 0 0; }
|
||||
.DMSDocumentAddController .ui-tabs ul.ui-tabs-nav li { padding-bottom: 1px; border: 1px solid #C0C0C2; }
|
||||
.DMSDocumentAddController .ui-tabs ul.ui-tabs-nav li a { padding: 8px 20px 8px; }
|
||||
|
||||
.ss-add .document-add-existing input.document-autocomplete { position: absolute; z-index: 9999; width: 390px; padding: 9px 7px; border-bottom-right-radius: 0; border-top-right-radius: 0; outline: none; box-sizing: border-box; -moz-box-sizing: border-box; }
|
||||
.ss-add .document-add-existing input.document-autocomplete[disabled] { color: #C0C0C2; text-shadow: 0 -1px 0 #FFF; background: #EEE; background-image: none; box-shadow: inset 0 1px 8px 0 #C4C4C4; border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
|
||||
.ss-add .document-add-existing .TreeDropdownField { border: none; width: 100%; max-width: 512px; box-sizing: border-box; cursor: pointer; }
|
||||
.ss-add .document-add-existing .treedropdownfield-toggle-panel-link { padding: 5px 9px 9px; background: #fff; border: 1px solid #B3B3B3; float: right; z-index: 99999; position: relative; }
|
||||
.ss-add .document-add-existing .treedropdownfield-toggle-panel-link.treedropdownfield-open-tree { background: #fff; border: 1px solid #B3B3B3; border-bottom: none; border-bottom-right-radius: 0; }
|
||||
.ss-add .document-add-existing .treedropdownfield-title { width: auto; }
|
||||
.ss-add .document-add-existing .treedropdownfield-toggle-panel-link a { display: inline-block; top: 4px; position: relative; }
|
||||
.ss-add .document-add-existing .document-list { width: 510px; border: 1px solid #DDD; border-top: none; background: #ffffff; display: none; box-shadow: 0 2px 4px 1px #DDD; max-height: 300px; border-radius: 6px; background-clip: padding-box; overflow: scroll; }
|
||||
.ss-add .document-add-existing .document-list p { padding: 10px 10px 0; }
|
||||
.ss-add .document-add-existing .document-list ul { padding: 4px 0; }
|
||||
.ss-add .document-add-existing .document-list ul li { line-height: 18px; }
|
||||
.ss-add .document-add-existing .document-list ul li a { display: block; padding: 4px 8px; border: 1px solid #FFF; color: black; }
|
||||
.ss-add .document-add-existing .document-list ul li a:hover { border: 1px solid #CCC; border-radius: 4px; background: rgba(203, 203, 203, 0.4); cursor: pointer; text-decoration: none; outline: none; text-shadow: none; }
|
||||
.ss-add .document-add-existing.link-editor-context label { float: left; display: block; width: 176px; padding: 8px 8px 8px 0; line-height: 16px; font-weight: bold; text-shadow: 1px 1px 0 white; }
|
||||
.ss-add .document-add-existing.link-editor-context .middleColumn { margin-left: 184px; }
|
||||
.ss-add .document-add-existing.link-editor-context .middleColumn input { background: white; border: 1px solid #B3B3B3; line-height: 16px; margin: 0; border-radius: 4px; background-size: 100%; max-width: 512px; }
|
||||
.ss-add .ss-assetuploadfield.link-editor-context label { float: left; display: block; width: 176px; padding: 8px 8px 8px 0; line-height: 16px; font-weight: bold; text-shadow: 1px 1px 0 white; }
|
||||
.ss-add .ss-assetuploadfield.link-editor-context .middleColumn { margin-left: 184px; display: block; padding: 8px 8px 8px 0; font-style: italic; min-height: 20px; }
|
||||
.ss-add .ss-assetuploadfield .step4 { margin-bottom: 10px; }
|
||||
|
||||
.cms .ss-add .treedropdownfield-panel, .cms .selectiongroup .treedropdownfield-panel { margin: -1px 0 0 0; box-sizing: border-box; }
|
||||
.cms .ss-add .treedropdownfield-panel ul, .cms .selectiongroup .treedropdownfield-panel ul { padding: 4px 0; }
|
||||
.cms .ss-add .treedropdownfield-panel ul li, .cms .selectiongroup .treedropdownfield-panel ul li { border: 1px solid #ffffff; }
|
||||
.cms .ss-add .treedropdownfield-panel ul li a, .cms .selectiongroup .treedropdownfield-panel ul li a { display: block; padding: 4px 2px; }
|
||||
.cms .ss-add .treedropdownfield-panel ul li a.jstree-hovered, .cms .selectiongroup .treedropdownfield-panel ul li a.jstree-hovered { background: rgba(203, 203, 203, 0.4); border: 1px solid #CCC; }
|
||||
|
||||
@-moz-document url-prefix() { .ss-add .document-add-existing input { padding: 10px 7px; } }
|
||||
|
||||
#Form_EditForm_Documents { padding: 1em 0; }
|
||||
#Form_EditForm_Documents input[name="filter[LastChanged]"] { display: none; }
|
||||
|
||||
#Form_EditForm_RelatedLinks table { padding: 1em 0; }
|
||||
#Form_EditForm_RelatedLinks table thead h2 { display: none; }
|
||||
|
||||
#SectionID .middleColumn, #DocumentTypeID .middleColumn { overflow: auto; min-width: 800px; }
|
||||
#SectionID .middleColumn ul, #DocumentTypeID .middleColumn ul { padding: 0; }
|
||||
#SectionID .middleColumn ul input[type="radio"], #DocumentTypeID .middleColumn ul input[type="radio"] { display: none; }
|
||||
#SectionID .middleColumn ul li, #DocumentTypeID .middleColumn ul li { display: table; padding: 0; width: 125px; height: 40px; white-space: normal; margin-right: -1px; border-radius: 0; }
|
||||
#SectionID .middleColumn ul li:first-child, #DocumentTypeID .middleColumn ul li:first-child { border-radius: 6px 0 0 6px; border-left: 1px solid #C0C0C2; }
|
||||
#SectionID .middleColumn ul li:last-child, #DocumentTypeID .middleColumn ul li:last-child { border-radius: 0 6px 6px 0; }
|
||||
#SectionID .middleColumn ul li.selected, .ie8 #SectionID .middleColumn ul li.selected, #DocumentTypeID .middleColumn ul li.selected, .ie8 #DocumentTypeID .middleColumn ul li.selected { border-bottom: 1px solid #C0C0C2; background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #c0c0c0), color-stop(100%, #e6e6e6)); background: -webkit-linear-gradient(#c0c0c0, #e6e6e6); background: -moz-linear-gradient(#c0c0c0, #e6e6e6); background: -o-linear-gradient(#c0c0c0, #e6e6e6); background: linear-gradient(#c0c0c0, #e6e6e6); background-color: silver; filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6'); /* IE6 & IE7 */ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6')"; /* IE8 */ box-shadow: 0 1px 1px 0 #A0A0A0 inset; }
|
||||
#SectionID .middleColumn ul li.selected :after, .ie8 #SectionID .middleColumn ul li.selected :after, #DocumentTypeID .middleColumn ul li.selected :after, .ie8 #DocumentTypeID .middleColumn ul li.selected :after { box-shadow: 0 1px 1px 0 #DDD; }
|
||||
#SectionID .middleColumn ul li label, #DocumentTypeID .middleColumn ul li label { display: table-cell; vertical-align: middle; text-align: center; padding: 0 10px; }
|
||||
|
||||
#Form_ItemEditForm h3:first-child { display: inline-block; float: left; width: 184px; }
|
||||
#Form_ItemEditForm ul.SelectionGroup { display: inline-block; position: relative; padding: 0; margin-top: 9px; margin-left: 0; height: 110px; background: none; border: none; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li { width: auto; clear: none; display: inline; margin-right: 4px; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li input.selector { display: none; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li label.ui-button { background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: -webkit-linear-gradient(#ffffff, #d9d9d9); background: -moz-linear-gradient(#ffffff, #d9d9d9); background: -o-linear-gradient(#ffffff, #d9d9d9); background: linear-gradient(#ffffff, #d9d9d9); font-weight: bold; border: 1px solid #C0C0C2; border-radius: 3px; padding: 0.8em 1.5em; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li label.ui-button:hover { box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); }
|
||||
#Form_ItemEditForm ul.SelectionGroup li div.field { margin-left: 0px; margin-bottom: 1em; width: 600px; position: absolute; left: 0; margin-top: 13px; padding: 10px; background: white; border: 1px solid #B3B3B3; -webkit-border-radius: 4px; -moz-border-radius: 4px; -ms-border-radius: 4px; -o-border-radius: 4px; border-radius: 4px; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #efefef), color-stop(10%, #ffffff), color-stop(90%, #ffffff), color-stop(100%, #efefef)); background-image: -webkit-linear-gradient(#efefef, #ffffff 10%, #ffffff 90%, #efefef); background-image: -moz-linear-gradient(#efefef, #ffffff 10%, #ffffff 90%, #efefef); background-image: -o-linear-gradient(#efefef, #ffffff 10%, #ffffff 90%, #efefef); background-image: linear-gradient(#efefef, #ffffff 10%, #ffffff 90%, #efefef); }
|
||||
#Form_ItemEditForm ul.SelectionGroup li.selected label.ui-button { border-bottom: 1px solid #C0C0C2; background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #c0c0c0), color-stop(100%, #e6e6e6)); background: -webkit-linear-gradient(#c0c0c0, #e6e6e6); background: -moz-linear-gradient(#c0c0c0, #e6e6e6); background: -o-linear-gradient(#c0c0c0, #e6e6e6); background: linear-gradient(#c0c0c0, #e6e6e6); background-color: silver; filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6'); /* IE6 & IE7 */ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6')"; /* IE8 */ box-shadow: 0 1px 1px 0 #A0A0A0 inset; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li.selected label.ui-button:after { content: ''; display: block; position: absolute; top: 33px; left: 50%; margin-left: -6px; width: 12px; height: 12px; background: #F8F8F8; border-right: 1px solid #B3B3B3; border-top: 1px solid #B3B3B3; -moz-transform: rotate(-45deg); -webkit-transform: rotate(-45deg); pointer-events: none; z-index: 10; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li.selected label.ui-button:after { top: 43px; }
|
||||
#Form_ItemEditForm ul.SelectionGroup .treedropdownfield-panel { margin: 1px 0 0 -1px; box-sizing: content-box; }
|
||||
#Form_ItemEditForm ul.SelectionGroup .treedropdownfield-panel ul li { display: block; clear: both; width: 100%; margin: 0; }
|
||||
#Form_ItemEditForm ul.SelectionGroup .treedropdownfield-panel ul li li { padding-left: 20px; }
|
|
@ -0,0 +1,331 @@
|
|||
.dmsdocument-documentdetails .fieldgroup-field .cms-file-info-preview {
|
||||
box-shadow: none; }
|
||||
|
||||
.dmsdocument-documentdetails .fieldgroup-field .cms-file-info-data {
|
||||
width: 400px; }
|
||||
|
||||
.dmsdocument-documentdetails .fieldgroup-field .fieldholder-small {
|
||||
margin-top: 5px; }
|
||||
.dmsdocument-documentdetails .fieldgroup-field .fieldholder-small .fieldholder-small-label {
|
||||
font-weight: bold;
|
||||
float: left; }
|
||||
.dmsdocument-documentdetails .fieldgroup-field .fieldholder-small .readonly {
|
||||
font-style: italic; }
|
||||
|
||||
.dmsdocment-actions {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
margin-bottom: 0;
|
||||
padding: 0; }
|
||||
.dmsdocment-actions label.left {
|
||||
padding: 6px 0 0 0; }
|
||||
.dmsdocment-actions .ss-ui-button {
|
||||
border: none;
|
||||
background: none;
|
||||
border-radius: 0;
|
||||
font-weight: normal; }
|
||||
.dmsdocment-actions .ss-ui-button .ui-button-text {
|
||||
padding-bottom: 1em; }
|
||||
.dmsdocment-actions .ss-ui-button.dms-active, .dmsdocment-actions .ss-ui-button.dms-active:hover {
|
||||
border-bottom: 4px solid #66727d; }
|
||||
.dmsdocment-actions .ss-ui-button:hover, .dmsdocment-actions .ss-ui-button:active {
|
||||
background: none;
|
||||
border: none;
|
||||
box-shadow: none; }
|
||||
|
||||
.dmsdocument-actionspanel {
|
||||
margin-top: 0; }
|
||||
.dmsdocument-actionspanel .fieldgroup {
|
||||
border: 1px solid #d0d3d5;
|
||||
display: none;
|
||||
margin-left: 0;
|
||||
padding: 5px 15px; }
|
||||
.dmsdocument-actionspanel .fieldgroup .fieldholder-small label {
|
||||
padding: 0; }
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo li,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry li {
|
||||
margin-left: 8px;
|
||||
width: 100%; }
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo li label,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry li label {
|
||||
padding-left: 10px; }
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime {
|
||||
float: left;
|
||||
margin-top: 0;
|
||||
margin-left: 34px;
|
||||
overflow: hidden; }
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime .field.date, .dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime .field.time,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime .field.date,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime .field.time,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime .field.date,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime .field.time,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime .field.date,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime .field.time {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: auto; }
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime .field.date .middleColumn, .dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime .field.time .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime .field.date .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime .field.time .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime .field.date .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime .field.time .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime .field.date .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime .field.time .middleColumn {
|
||||
overflow: hidden; }
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime .field.date .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime .field.date .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime .field.date .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime .field.date .middleColumn {
|
||||
background: url(../../images/calendar-month.png) 90px 7px no-repeat; }
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime .field.time .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime .field.time .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime .field.time .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime .field.time .middleColumn {
|
||||
background: url(../../images/clock-frame.png) 90px 7px no-repeat; }
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime .middleColumn,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime .middleColumn {
|
||||
border: none;
|
||||
margin-left: 0;
|
||||
width: auto; }
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime .middleColumn input.date,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .embargoDatetime .middleColumn input.time,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime .middleColumn input.date,
|
||||
.dmsdocument-actionspanel .fieldgroup .embargo .expiryDatetime .middleColumn input.time,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime .middleColumn input.date,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .embargoDatetime .middleColumn input.time,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime .middleColumn input.date,
|
||||
.dmsdocument-actionspanel .fieldgroup .expiry .expiryDatetime .middleColumn input.time {
|
||||
margin-right: 40px;
|
||||
width: 80px; }
|
||||
.dmsdocument-actionspanel .fieldgroup .fieldgroup-field label {
|
||||
margin: 0; }
|
||||
.dmsdocument-actionspanel .ss-uploadfield-files .ss-uploadfield-item-preview {
|
||||
background: url(../../images/app_icons/generic_32.png) -10px -6px no-repeat; }
|
||||
.dmsdocument-actionspanel .ss-uploadfield-files .ss-uploadfield-item-name span.name {
|
||||
width: 260px; }
|
||||
.dmsdocument-actionspanel .ss-uploadfield-files .ss-uploadfield-item-actions .ss-uploadfield-item-cancel {
|
||||
text-indent: 0;
|
||||
width: auto; }
|
||||
.dmsdocument-actionspanel .ss-uploadfield-files .ss-uploadfield-item-actions .ss-uploadfield-item-cancel .btn-icon-deleteLight {
|
||||
background-position: 0 -128px;
|
||||
display: inline-block; }
|
||||
.dmsdocument-actionspanel .ss-uploadfield-files .ss-uploadfield-item-actions .ss-uploadfield-item-cancel .ui-button-text {
|
||||
color: #66727d;
|
||||
display: block;
|
||||
float: right;
|
||||
padding: 0 0 0 2em;
|
||||
position: relative; }
|
||||
.dmsdocument-actionspanel > .fieldgroup.middleColumn {
|
||||
display: block;
|
||||
overflow: hidden; }
|
||||
.dmsdocument-actionspanel > .fieldgroup.middleColumn .fieldgroup-field {
|
||||
width: 100%; }
|
||||
.dmsdocument-actionspanel .permissions .fieldholder-small {
|
||||
clear: both; }
|
||||
|
||||
#ui-datepicker-div {
|
||||
border: 1px solid #d0d3d5; }
|
||||
|
||||
form.small .field input.text,
|
||||
form.small .field textarea,
|
||||
form.small .field select,
|
||||
form.small .field .TreeDropdownField,
|
||||
.field.small input.text,
|
||||
.field.small textarea,
|
||||
.field.small select,
|
||||
.field.small .TreeDropdownField {
|
||||
width: 100%; }
|
||||
|
||||
.dmsdocument-addexisting .ui-autocomplete {
|
||||
border: 1px solid #d0d3d5;
|
||||
max-height: 300px;
|
||||
overflow: scroll; }
|
||||
|
||||
.ss-add .document-add-existing input.document-autocomplete {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
width: 390px;
|
||||
padding: 9px 7px;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box; }
|
||||
.ss-add .document-add-existing input.document-autocomplete[disabled] {
|
||||
color: #d0d3d5;
|
||||
text-shadow: 0 -1px 0 #ffffff;
|
||||
background: #f8f8f8;
|
||||
background-image: none;
|
||||
box-shadow: inset 0 1px 8px 0 #d0d3d5;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.ss-add .document-add-existing .treedropdown {
|
||||
border: none; }
|
||||
|
||||
.ss-add .document-add-existing .treedropdownfield-toggle-panel-link {
|
||||
padding: 5px 9px 9px;
|
||||
background: #fff;
|
||||
border: 1px solid #b3b3b3;
|
||||
float: right;
|
||||
z-index: 99999;
|
||||
position: relative; }
|
||||
.ss-add .document-add-existing .treedropdownfield-toggle-panel-link.treedropdownfield-open-tree {
|
||||
background: #fff;
|
||||
border: 1px solid #b3b3b3;
|
||||
border-bottom: none;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.ss-add .document-add-existing .treedropdownfield-title {
|
||||
width: auto; }
|
||||
|
||||
.ss-add .document-add-existing .treedropdownfield-toggle-panel-link a {
|
||||
display: inline-block;
|
||||
top: 4px;
|
||||
position: relative; }
|
||||
|
||||
.ss-add .document-add-existing .document-list {
|
||||
width: 510px;
|
||||
border: 1px solid #d0d3d5;
|
||||
border-top: none;
|
||||
background: #ffffff;
|
||||
display: none;
|
||||
max-height: 300px;
|
||||
background-clip: padding-box;
|
||||
overflow: scroll; }
|
||||
.ss-add .document-add-existing .document-list p {
|
||||
padding: 10px 10px 0; }
|
||||
.ss-add .document-add-existing .document-list ul {
|
||||
padding: 4px 0; }
|
||||
.ss-add .document-add-existing .document-list ul li {
|
||||
line-height: 18px; }
|
||||
.ss-add .document-add-existing .document-list ul li a {
|
||||
display: block;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid #ffffff;
|
||||
color: black; }
|
||||
.ss-add .document-add-existing .document-list ul li a:hover {
|
||||
border: 1px solid #d0d3d5;
|
||||
border-radius: 4px;
|
||||
background: rgba(203, 203, 203, 0.4);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
text-shadow: none; }
|
||||
|
||||
.ss-add .document-add-existing.link-editor-context label {
|
||||
float: left;
|
||||
display: block;
|
||||
width: 176px;
|
||||
padding: 8px 8px 8px 0;
|
||||
line-height: 16px;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px 0 white; }
|
||||
|
||||
.ss-add .document-add-existing.link-editor-context .middleColumn input {
|
||||
background: white;
|
||||
border: 1px solid #b3b3b3;
|
||||
line-height: 16px;
|
||||
border-radius: 4px;
|
||||
background-size: 100%;
|
||||
max-width: 468px; }
|
||||
.ss-add .document-add-existing.link-editor-context .middleColumn input.document-autocomplete {
|
||||
max-width: 365px; }
|
||||
|
||||
.ss-add .document-add-existing.link-editor-context .document-list {
|
||||
width: calc(100% - 2px); }
|
||||
|
||||
.ss-add .ss-assetuploadfield.link-editor-context label {
|
||||
float: left;
|
||||
display: block;
|
||||
width: 176px;
|
||||
padding: 8px 8px 8px 0;
|
||||
line-height: 16px;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px 0 white; }
|
||||
|
||||
.ss-add .ss-assetuploadfield.link-editor-context .middleColumn {
|
||||
margin-left: 184px;
|
||||
display: block;
|
||||
padding: 8px 8px 8px 0;
|
||||
font-style: italic;
|
||||
min-height: 20px; }
|
||||
|
||||
.ss-add .ss-assetuploadfield .step4 {
|
||||
margin-bottom: 10px; }
|
||||
|
||||
.cms .ss-add .treedropdownfield-panel,
|
||||
.cms .selectiongroup .treedropdownfield-panel {
|
||||
margin: -1px 0 0 0;
|
||||
box-sizing: border-box; }
|
||||
.cms .ss-add .treedropdownfield-panel ul,
|
||||
.cms .selectiongroup .treedropdownfield-panel ul {
|
||||
padding: 4px 0; }
|
||||
.cms .ss-add .treedropdownfield-panel ul li,
|
||||
.cms .selectiongroup .treedropdownfield-panel ul li {
|
||||
border: 1px solid #ffffff; }
|
||||
.cms .ss-add .treedropdownfield-panel ul li a,
|
||||
.cms .selectiongroup .treedropdownfield-panel ul li a {
|
||||
display: block;
|
||||
padding: 4px 2px; }
|
||||
.cms .ss-add .treedropdownfield-panel ul li a.jstree-hovered,
|
||||
.cms .selectiongroup .treedropdownfield-panel ul li a.jstree-hovered {
|
||||
background: rgba(203, 203, 203, 0.4);
|
||||
border: 1px solid #d0d3d5; }
|
||||
|
||||
#Form_ItemEditForm h3:first-child {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
width: 184px; }
|
||||
|
||||
#Form_ItemEditForm ul.SelectionGroup {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin-top: 9px;
|
||||
margin-left: 0;
|
||||
height: 110px;
|
||||
background: none;
|
||||
border: none; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li {
|
||||
width: auto;
|
||||
clear: none;
|
||||
display: inline;
|
||||
margin-right: 4px; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li input.selector {
|
||||
display: none; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li label.ui-button {
|
||||
font-weight: bold;
|
||||
border: 1px solid #C0C0C2;
|
||||
border-radius: 3px;
|
||||
padding: 0.8em 1.5em; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li label.ui-button:hover {
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); }
|
||||
#Form_ItemEditForm ul.SelectionGroup li div.field {
|
||||
margin-left: 0px;
|
||||
margin-bottom: 1em;
|
||||
width: 600px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
margin-top: 13px;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
border: 1px solid #b3b3b3; }
|
||||
#Form_ItemEditForm ul.SelectionGroup li.selected label.ui-button:after {
|
||||
top: 43px; }
|
||||
#Form_ItemEditForm ul.SelectionGroup .treedropdownfield-panel {
|
||||
margin: 1px 0 0 -1px;
|
||||
box-sizing: content-box; }
|
||||
#Form_ItemEditForm ul.SelectionGroup .treedropdownfield-panel ul li {
|
||||
display: block;
|
||||
clear: both;
|
||||
width: 100%;
|
||||
margin: 0; }
|
||||
#Form_ItemEditForm ul.SelectionGroup .treedropdownfield-panel ul li li {
|
||||
padding-left: 20px; }
|
|
@ -0,0 +1,28 @@
|
|||
# Building frontend assets
|
||||
|
||||
This guide is intended for instructions on dealing with frontend asset files while contributing to this module. You
|
||||
could also extend the Javascript and/or SCSS files using a combination of your own Webpack configurations and
|
||||
`Requirements::block` calls (to block the default DMS assets), but this is not the primary intent of this document.
|
||||
|
||||
## Javascript
|
||||
|
||||
Javascript files use jQuery entwine, and live in the `javascript` folder. You can edit these files directly.
|
||||
|
||||
## SASS/CSS
|
||||
|
||||
CSS is build using Webpack and the sass-loader plugin. To install the required dependencies, you will need NodeJS and
|
||||
npm installed on your local machine. You can then install by running `npm install` from the `dms` module folder.
|
||||
|
||||
To make changes to CSS you need to first make the change in the relevant SCSS file in the `scss` folder.
|
||||
|
||||
You can then compile the SCSS into CSS files:
|
||||
|
||||
```
|
||||
npm run build
|
||||
# or, to watch:
|
||||
npm run watch
|
||||
```
|
||||
|
||||
This will compile the SCSS files and produce a single compiled file under `dist/css/cmsbundle.css`. This file is named
|
||||
this way to distinguish the fact that its contents are all related to the CMS rather than the frontend of a SilverStripe
|
||||
website.
|
|
@ -0,0 +1,46 @@
|
|||
# 2.0.0 (unreleased)
|
||||
|
||||
## Document sets
|
||||
|
||||
Documents now belong to "sets", which are attached to Pages. A Page can have many Document Sets, and a Set has a
|
||||
many_many relationship with Documents.
|
||||
|
||||
When upgrading from 1.x to 2.x you will need to migrate the relationships from your Pages to Documents to support
|
||||
having a Document Set intermediary. [See here](../migration/document-sets.md) for an example build task to help with
|
||||
this process.
|
||||
|
||||
## API changes
|
||||
|
||||
* `DMSSiteTreeExtension::no_documents_tab` removed, use YAML configuration `MyPage.documents_enabled: false` instead
|
||||
* `DMSSiteTreeExtension::show_documents_tab` removed, use YAML configuration `MyPage.documents_enabled: true` instead
|
||||
* `DMSSiteTreeExtension::PageDocuments` removed, use `DMSSiteTreeExtension::getDocumentSets` instead
|
||||
* `DMSSiteTreeExtension::getDocuments` removed, use `DMSSiteTreeExtension::getAllDocuments` instead
|
||||
* `DMSDocument::addPage` removed, use document sets instead
|
||||
* `DMSDocument::addPages` removed, use document sets instead
|
||||
* `DMSDocument::removePage` removed, use document sets instead
|
||||
* `DMSDocument::removeAllPages` removed, use document sets instead
|
||||
* `DMSDocument::getPages` removed, use `DMSDocument::getRelatedPages` instead
|
||||
* `DMSDocumentInterface` has had the page manipulation methods removed, as above
|
||||
* `DMSDocumentAddController::add_allowed_extensions` removed, use YAML configuration `DMSDocumentAddController::allowed_extensions` instead
|
||||
* `DMSInterface` (and `DMS`) are stricter in the `getByPage` method, enforcing a `SiteTree` type hint
|
||||
* New method `DMSInterface::getDocumentSetsByPage` (and in `DMS`)
|
||||
* `DMS::$dmsFolder` removed, use YAML configuration `DMS.folder_name` instead
|
||||
* `DMS::$dmsFolderSize` removed, use YAML configuration `DMS.folder_size` instead
|
||||
* `DMS::get_dms_path` made non-static, use `DMS::inst()->getStoragePath()` instead
|
||||
* `DMS::transform_file_to_file_path` made non-static, use `DMS::inst()->transformFileToFilePath()` instead
|
||||
* `DMS::create_storage_folder` made non-static, use `DMS::inst()->createStorageFolder()` instead
|
||||
* `DMS::get_storage_folder` made non-static, use `DMS::inst()->getStorageFolder()` instead
|
||||
* `DMSDocument::addTag`, `::getTagsList`, `::removeTag` and `::removeAllTags` removed from the `DMSDocument` and `DMSDocumentInterface`. Please use the ORM relationship created by applying the `DMSDocumentTaxonomyExtension` extension to `DMSDocument` instead.
|
||||
* `DMSInterface::getByTag` removed from `DMSInterface` and `DMS`. Use ORM relationships from applying `DMSDocumentTaxonomyExtension` to `DMSDocument` instead.
|
||||
* `DMSGridFieldDeleteAction` removed
|
||||
* `DMSDocument::getFileName` renamed to `DMSDocument::getFilename` for consistency
|
||||
|
||||
## Template changes
|
||||
|
||||
The default template entry point is now `DocumentSets.ss` (previously `Documents.ss`). As well as this change,
|
||||
`Documents.ss` has been renamed to `DocumentSet.ss`.
|
||||
|
||||
## Frontend assets
|
||||
|
||||
We've removed the configuration for using Compass to build SCSS. You can now use Webpack instead.
|
||||
[See here](building-frontend-assets.md) for more information on this.
|
|
@ -0,0 +1,91 @@
|
|||
# Configuration
|
||||
|
||||
The file location is set via the `DMS.folder_name` configuation property, and points to a location in the webroot. By
|
||||
default, this resides in an underscores folder within the assets folder. This means that automated snapshots/backups
|
||||
(e.g. using [sspak](https://github.com/silverstripe/sspak)) can still handle DMS documents, but they will not show up
|
||||
when navigating asset folders in the CMS.
|
||||
|
||||
## Changing the default storage folder
|
||||
|
||||
You can change the default storage folder location using YAML configuration. This folder would be relative to your
|
||||
project root directory:
|
||||
|
||||
```yaml
|
||||
DMS:
|
||||
folder_name: my-custom-folder
|
||||
```
|
||||
|
||||
|
||||
## Enable/disable documents/sets for a specific page type
|
||||
|
||||
If you don't need documents/document sets for a specific page type you can disable this with YAML configuration:
|
||||
|
||||
```yaml
|
||||
MyPageType:
|
||||
documents_enabled: false
|
||||
```
|
||||
|
||||
Likewise, you could override a previously set configuration value by setting this back to `true` in a configuration
|
||||
file with a higher precedence.
|
||||
|
||||
## Allowed extensions for DMS documents
|
||||
|
||||
By default the allowed extensions for DMS documents will come from the UploadField's allowed extesions list, and will
|
||||
have a customised list of extensions for DMS merged in. The base `allowed_extensions` is a site-wide configuration
|
||||
setting. [See here for information](https://docs.silverstripe.org/en/3/developer_guides/forms/field_types/uploadfield/#limit-the-allowed-filetypes) on changing this.
|
||||
|
||||
To add extra allowed file extensions purely for DMS documents, you can update the YAML configuration property:
|
||||
|
||||
```yaml
|
||||
DMSDocumentAddController:
|
||||
allowed_extensions:
|
||||
- php
|
||||
- php5
|
||||
```
|
||||
|
||||
## Adding fields to the Query Builder
|
||||
Query builder fields are read from the DMSDocument::searchable_fields property set in [querybuilder.yml](../../_config/querybuilder.yml). Some default fields are provided and can be customised
|
||||
by modifying the field and/or filter properties of a field or adding a new field entirely.
|
||||
|
||||
[See here for information](https://docs.silverstripe.org/en/developer_guides/model/searchfilters/) on how to modify search filters and [see here for more information](https://docs.silverstripe.org/en/developer_guides/forms/field_types/common_subclasses/)
|
||||
on the field types available.
|
||||
|
||||
The default searchable filters available to query builder is as follows:
|
||||
|
||||
```yaml
|
||||
DMSDocument:
|
||||
searchable_fields:
|
||||
Title:
|
||||
title: "Document title matches ..."
|
||||
Description:
|
||||
title: "Document summary matches ..."
|
||||
CreatedByID:
|
||||
title: 'Document created by ...'
|
||||
field: 'ListboxField'
|
||||
filter: 'ExactMatchFilter'
|
||||
LastEditedByID:
|
||||
title: 'Document last changed by ...'
|
||||
field: 'ListboxField'
|
||||
filter: 'ExactMatchFilter'
|
||||
Filename:
|
||||
title: 'File name'
|
||||
```
|
||||
|
||||
## Change the shortcode handler
|
||||
|
||||
If you need to change the `dms_document_link` shortcode handler for some reason, you can do so with YAML configuration
|
||||
and some PHP:
|
||||
|
||||
```yaml
|
||||
DMS:
|
||||
shortcode_handler_key: your_shortcode
|
||||
```
|
||||
|
||||
And for example in `_config.php`:
|
||||
|
||||
```php
|
||||
ShortcodeParser::get('default')->register(
|
||||
Config::inst()->get('DMS', 'shortcode_handler_key'),
|
||||
array('DMSShortcodeHandler', 'handle')
|
||||
);
|
||||
```
|
|
@ -0,0 +1,35 @@
|
|||
# Creating documents
|
||||
|
||||
The following examples will allow you to create a DMS document in the system without associating it to a document set.
|
||||
|
||||
## Create by relative path
|
||||
|
||||
```php
|
||||
$dms = DMS::inst();
|
||||
$doc = $dms->storeDocument('assets/myfile.pdf');
|
||||
```
|
||||
|
||||
## Create from an existing `File` record
|
||||
|
||||
```php
|
||||
$dms = DMS::inst();
|
||||
$file = File::get()->byID(99);
|
||||
$doc = $dms->storeDocument($file);
|
||||
```
|
||||
|
||||
Note: Both operations copy the existing file.
|
||||
|
||||
## Associate to a document set
|
||||
|
||||
If you need to associate a document to a set once it has already been created, you can use the ORM relationship from
|
||||
SiteTree to access the document sets, or you can simply access the document set directly:
|
||||
|
||||
```php
|
||||
// Add document to the first set in my page
|
||||
$firstSetInPage = $myPage->DocumentSets()->first();
|
||||
$firstSetInPage->add($doc);
|
||||
|
||||
// Add document to a specific document set
|
||||
$docSet = DMSDocumentSet::get()->byId(123);
|
||||
$docSet->add($doc);
|
||||
```
|
|
@ -0,0 +1,18 @@
|
|||
# Documents on the Filesystem
|
||||
|
||||
While the DMS architecture allows for remote storage of files, the default implementation (the `DMS` class)
|
||||
stores them locally. Relations to pages and tags are persisted as many-many relationships through the SilverStripe ORM.
|
||||
|
||||
File locations in this implementation are structured into subfolders, in order to avoid exceeding filesystem limits.
|
||||
The file name is a composite based on its database ID and the original file name. The exact location shouldn't be
|
||||
relied on by custom logic, but rather retrieved through the API method `DMSDocument::getLink`.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
dms-assets/
|
||||
0/
|
||||
1234~myfile.pdf
|
||||
1/
|
||||
2345~myotherfile.pdf
|
||||
```
|
|
@ -0,0 +1,27 @@
|
|||
# Download documents
|
||||
|
||||
## Get the download link
|
||||
|
||||
You can use `DMSDocument::getLink` to retrieve the secure route to download a DMS document:
|
||||
|
||||
```php
|
||||
$document = DMSDocument::get()->byId(123);
|
||||
$link = $document->getLink();
|
||||
```
|
||||
|
||||
## Default download behaviour
|
||||
|
||||
The default download behaviour is "download" which will force the browser to download the document. You
|
||||
can select "open" as an option in the document's settings in the CMS individually, or you can change the global
|
||||
default value with configuration:
|
||||
|
||||
```php
|
||||
Config::inst()->update('DMSDocument', 'default_download_behaviour', 'open');
|
||||
```
|
||||
|
||||
Or in YAML:
|
||||
|
||||
```yaml
|
||||
DMSDocument:
|
||||
default_download_behaviour: open
|
||||
```
|
|
@ -0,0 +1,20 @@
|
|||
# DMS documentation
|
||||
|
||||
## Development
|
||||
|
||||
* [Configuration](configuration.md)
|
||||
* [Documents on the filesystem](documents-on-the-filesystem.md)
|
||||
* [Use in templates](use-in-templates.md)
|
||||
* [Creating documents](creating-documents.md)
|
||||
* [Download documents](download-documents.md)
|
||||
* [Manage page relations](manage-page-relations.md)
|
||||
* [Manage related documents](manage-related-documents.md)
|
||||
* [Building frontend assets](building-frontend-assets.md)
|
||||
|
||||
## CMS user help
|
||||
|
||||
* [DMS user guide](userguide/index.md)
|
||||
|
||||
### Changelogs
|
||||
|
||||
* [2.0.0 (unreleased)](changelogs/2.0.0.md)
|
|
@ -0,0 +1,35 @@
|
|||
# Manage page relations
|
||||
|
||||
Documents are associated to pages via "document sets". You can retrieve document sets for a page, then retrieve
|
||||
documents that belong to those sets. You can still retrieve all documents for a page if you want to.
|
||||
|
||||
## Get document sets for a page
|
||||
|
||||
```php
|
||||
$dms = DMS::inst();
|
||||
$sets = $dms->getDocumentSetsByPage($myPage);
|
||||
```
|
||||
|
||||
You can also request sets directly from the SiteTree instance:
|
||||
|
||||
```php
|
||||
$sets = $page->getDocumentSets();
|
||||
```
|
||||
|
||||
## Get all related documents for a page
|
||||
|
||||
`DMS::getByPage` will exclude currently embargoed documents by default. To include embargoed documents as well
|
||||
add `true` as the second argument.
|
||||
|
||||
```php
|
||||
$dms = DMS::inst();
|
||||
|
||||
$documents = $dms->getByPage($myPage);
|
||||
$documentsIncludingEmbargoed = $dms->getByPage($myPage, true);
|
||||
```
|
||||
|
||||
You can also request this directly from the SiteTree instance:
|
||||
|
||||
```php
|
||||
$documents = $myPage->getAllDocuments();
|
||||
```
|
|
@ -0,0 +1,50 @@
|
|||
# Manage related documents
|
||||
|
||||
You can relate documents to each other using the GridField under "Related Documents" in the CMS.
|
||||
|
||||
## Add related documents
|
||||
|
||||
You can use the model relationship `DMSDocument::RelatedDocuments` to modify the DataList and save as required:
|
||||
|
||||
```php
|
||||
$parentDocument = DMSDocument::get()->byId(123);
|
||||
|
||||
$relatedDocument = DMSDocument::get()->byId(234);
|
||||
|
||||
$parentDocument->RelatedDocuments()->add($relatedDocument);
|
||||
```
|
||||
|
||||
Using the relationship method directly will skip the extension hook available in `getRelatedDocuments` (see below).
|
||||
|
||||
## Modifying the related documents list
|
||||
|
||||
If you need to modify the related documents DataList returned by the ORM, use the `updateRelatedDocuments` extension
|
||||
hook provided by `DMSDocument::getRelatedDocuments`:
|
||||
|
||||
```php
|
||||
# MyExtension is an extension applied to DMSDocument
|
||||
class MyExtension extends DataExtension
|
||||
{
|
||||
public function updateRelatedDocuments($relatedDocuments)
|
||||
{
|
||||
foreach ($relatedDocuments as $document) {
|
||||
// Add square brackets around the description
|
||||
$document->Description = '[' . $document->Description . ']';
|
||||
}
|
||||
return $relatedDocuments;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Retrieving related documents
|
||||
|
||||
To retrieve a DataList of related documents you can either use `getRelatedDocuments` or the ORM relationship method
|
||||
`RelatedDocuments` directly. The former will allow extensions to modify the list, whereas the latter will not.
|
||||
|
||||
```php
|
||||
$relatedDocuments = $document->getRelatedDocuments();
|
||||
|
||||
foreach ($relatedDocuments as $relatedDocument) {
|
||||
// ...
|
||||
}
|
||||
```
|
|
@ -0,0 +1,142 @@
|
|||
# Migrating to use Document Sets
|
||||
|
||||
> **Warning!** Please ensure you take a backup of your database before performing any of these migration task steps.
|
||||
|
||||
Version 2.0.0 of the DMS module introduces document sets as the containing relationship for pages and documents. In
|
||||
previous versions of DMS the relationship was between pages and documents directly.
|
||||
|
||||
If you are migrating from an earlier version of DMS to 2.x, you will need to set up new document sets for each page
|
||||
that contained documents and establish the links from the old document-page to the new document set-document, and
|
||||
document set-page.
|
||||
|
||||
We have included a migration build task that you can use to automate this process. It can be access via
|
||||
`/dev/tasks/MigrateToDocumentSetsTask`, and will prompt you for the following steps in the migration process:
|
||||
|
||||
* Create a default document set for all valid pages (see note)
|
||||
* Re-assign documents to their original page's new document set
|
||||
|
||||
## Using the migration build task
|
||||
|
||||
### Enabling dry run mode
|
||||
|
||||
For either of the "actions" in this build task, you can enable dry run mode to see what the results will be without
|
||||
it actually writing anything in the database. We advise you do this as a first step.
|
||||
|
||||
You can enable dryrun mode by adding `dryrun=1` as an argument.
|
||||
|
||||
Example output will contain the following when dryrun mode is enabled:
|
||||
|
||||
```plain
|
||||
NOTE: Dryrun mode enabled. No changes will be written.
|
||||
```
|
||||
|
||||
### 1. Create a default document set
|
||||
|
||||
The first step of the migration build task will find all pages that do not have documents disabled (see note) and will
|
||||
create a document set called "Default" if one does not already exist. In the case where a document set already exists
|
||||
for a page, it will be used as the default.
|
||||
|
||||
Run from command line:
|
||||
|
||||
```plain
|
||||
sake dev/tasks/MigrateToDocumentSetsTask action=create-default-document-set
|
||||
```
|
||||
|
||||
Run from a browser:
|
||||
|
||||
```plain
|
||||
http://yoursite.dev/dev/tasks/MigrateToDocumentSetsTask?action=create-default-document-set
|
||||
```
|
||||
|
||||
An example output from this task might look like this:
|
||||
|
||||
```plain
|
||||
Running Task DMS 2.0 Migration Tool
|
||||
|
||||
Migrating DMS data to 2.x for document sets
|
||||
|
||||
Finished:
|
||||
+ Default document set added: 6
|
||||
+ Skipped: documents disabled: 1
|
||||
```
|
||||
|
||||
This task will only write records for those that are needed. If you run it more than once it will simply not do
|
||||
anything.
|
||||
|
||||
### 2. Re-assign documents
|
||||
|
||||
> **Note!** If you want to choose specific document sets for documents to be assigned to rather than just the first
|
||||
belonging to a page, you will need to run these queries manually (see further in this document).
|
||||
|
||||
The second step in the migration task is to reassign the relationship from pages to documents to document set to
|
||||
documents. This task assumes that the original relationship data is still present in the database, since SilverStripe
|
||||
will not remove old columns from the database tables once they've been made obsolete.
|
||||
|
||||
Run from command line:
|
||||
|
||||
```plain
|
||||
sake dev/tasks/MigrateToDocumentSetsTask action=reassign-documents
|
||||
```
|
||||
|
||||
Run from a browser:
|
||||
|
||||
```plain
|
||||
http://yoursite.dev/dev/tasks/MigrateToDocumentSetsTask?action=reassign-documents
|
||||
```
|
||||
|
||||
An example output from this task might look like this:
|
||||
|
||||
```plain
|
||||
Running Task DMS 2.0 Migration Tool
|
||||
|
||||
Migrating DMS data to 2.x for document sets
|
||||
|
||||
Finished:
|
||||
+ Reassigned to document set: 4
|
||||
```
|
||||
|
||||
This task will show the same output on the initial and subsequent runs. You can follow the instructions below to clean
|
||||
up legacy data after you've validated that everything is working correctly if you'd like to.
|
||||
|
||||
## Cleanup
|
||||
|
||||
Since SilverStripe will not remove the old obselete relationship table from the database, you can remove it manually
|
||||
if required. Only do this once you've validated that everything has been migrated correctly.
|
||||
|
||||
```sql
|
||||
DROP TABLE `your_ss_database`.`DMSDocument_Pages`;
|
||||
```
|
||||
|
||||
## Migrating data manually
|
||||
|
||||
As mentioned earlier, if you need to migrate data manually for one reason or another you can do so with a couple of
|
||||
manual SQL queries to the database.
|
||||
|
||||
One example of why you may need to do this is if you don't want your documents to
|
||||
be automatically assigned to the "default" document set on a page, but would prefer to choose a specific set to assign
|
||||
to. The automated build task cannot make this decision for us, but you can run some queries yourself.
|
||||
|
||||
In DMS 1.x the relationship of documents to pages is stored in the `DMSDocument_Pages` table. If you run an explain
|
||||
query you will see some obviously named foreign key columns for `DMSDocumentID` and `SiteTreeID`.
|
||||
|
||||
In DMS 2.x the relationship is of document _sets_ to documents, and is stored in `DMSDocumentSet_Documents`.
|
||||
|
||||
How you manipulate this data is up to you, but an example might be that you want to move a certain range of documents
|
||||
by their IDs into a specific document set (by its ID), so you could run the following:
|
||||
|
||||
```sql
|
||||
-- Insert the new records
|
||||
INSERT INTO `your_ss_database`.`DMSDocumentSet_Documents`
|
||||
(`DMSDocumentSetID`, `DMSDocumentID`)
|
||||
SELECT
|
||||
-- your document set ID
|
||||
123,
|
||||
`ID`
|
||||
FROM `your_ss_database`.`DMSDocument` WHERE `ID` IN(1, 2, 3, 4); -- your document IDs
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
> Create a default document set for all valid pages
|
||||
|
||||
"Valid pages" means that the page class does not have the `documents_enabled` configuration property set to `false`.
|
|
@ -0,0 +1,11 @@
|
|||
# Use in templates
|
||||
|
||||
Add a simple include to any of your `.ss` templates to display the DMSDocuments associated with
|
||||
the current page on the front-end.
|
||||
|
||||
```
|
||||
<% include DocumentSets %>
|
||||
```
|
||||
|
||||
You can fine tune the HTML markup or display behaviour of any of the templates in `/dms/templates/Includes` to change
|
||||
the way documents will be displayed in your project.
|
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 65 KiB |
|
@ -0,0 +1,3 @@
|
|||
# Document Management System Cart Module
|
||||
|
||||
You can now request a hard-copy of preconfigured documents using the [DMS Cart Module](https://github.com/creative-commoners/silverstripe-dms-cart). The Cart Module is similar to a shopping cart and allows multiple documents to be requested in print form. This is an optional installation to enhance your DMS.
|
|
@ -0,0 +1,71 @@
|
|||
# Document set management
|
||||
|
||||
## Creating a Document Set
|
||||
|
||||
You can create Document Sets directly on a **Page** or in the **Documents** section.
|
||||
|
||||
In the **Documents** section, go to the new tab "Document Set", then use the button "Add Document Set" to create a new document set.
|
||||
|
||||
![Example of deleting a document set](_images/document_section.png)
|
||||
|
||||
If you want to create a Document Set directly from a page, navigate to the page, select the "Document Set" tab and the same "Add Document Set" button will appear.
|
||||
|
||||
![Example of deleting a document set](_images/pages_section.png)
|
||||
|
||||
Clicking the "Add Document Set" button will prompt you to fill in two fields: "Title" and "Show on page".
|
||||
|
||||
![Example of deleting a document set](_images/document_set.png)
|
||||
|
||||
The "Title" is the name of the document set that is used for display and searching purposes. The "Show on page" dropdown will let you immediately assign this document set to a page.
|
||||
|
||||
If you don't want to assign a document set to a page right now, you can leave it blank – although the title for your new document set is compulsory. Once you’ve given it a name, click "Create".
|
||||
|
||||
## Adding documents to a Document Set
|
||||
|
||||
As soon as you create a Document Set you can add documents to it, regardless of where it was created from. You can do this by clicking "Add Document".
|
||||
|
||||
The "Add Documents" page allows you to upload a file directly from your computer; either select "Choose files to upload" if you want to find the files in your file system using a navigation tool; or just drag-and-drop the files into the "Drop Area".
|
||||
|
||||
Alternatively, you can add documents to your new Document Set that already exist in the CMS. To do this, just select the "From the CMS" tab and search for the filename or browse by the page that document is on.
|
||||
|
||||
_**Note:** All of your documents will be uploaded into the "Documents" section's "Document" tab. Uploading documents in the "Documents" section works the same way as uploading files in the "Files" section. The only difference is that DMS documents are invisible to parts of SilverStripe CMS that handle files, meaning that they cannot be selected via the "Insert File" button when editing HTML content on a page, for example. They also have a higher level of security permissions and flexibility. You can read more about_ [working with images and documents](https://userhelp.silverstripe.org/en/creating_pages_and_content/creating_and_editing_content/working_with_images_and_documents/).
|
||||
|
||||
After uploading your documents click "Done!". You will then be taken back to that document set. You will see your documents in a list with their ID and filename, along with other information such as when the document was last edited and how the documents were added to the document set.
|
||||
|
||||
**Tip:** If you have the [sortablegridfield module](http://addons.silverstripe.org/add-ons/undefinedoffset/sortablegridfield) installed, you can reorder the documents in the list by drag-and-dropping them.
|
||||
|
||||
![Example of deleting a document set](_images/sortablegridfield.png)
|
||||
|
||||
## Assigning a document set to a page
|
||||
|
||||
Head to the **Pages** section, click "Home" and go to the "Document Sets" tab. You can "Link existing" by using the _"Find Document Sets by Title"_ search bar to add an existing document set. To link existing document sets, start typing into the "link existing" search box and an autocompleted list of document sets that are not already assigned to a page will be displayed. Select the set you want from the results and click "Link Existing" to link it to the current page.
|
||||
|
||||
![Example of deleting a document set](_images/link_existing.png)
|
||||
|
||||
You can add and edit document sets while in the "Document Sets" tab attached to a page, or from the **Documents** section in the CMS. Both methods work the same way.
|
||||
|
||||
## Unlinking a document set from a page
|
||||
|
||||
If you want to remove a Document Set from a page, go to "Document Sets" tab and then use the "Unlink" button. This won't delete the Document Set, but will stop displaying that set on that page.
|
||||
|
||||
![Example of deleting a document set](_images/unlink_doc_set.png)
|
||||
|
||||
## Deleting a Document Set
|
||||
|
||||
To delete a Document Set, you must navigate to the **Documents** section. Click the "Document Set" tab and click on the delete icon on the right hand side of the set you want to delete. This will bring up a dialog box confirming if you want to delete the set. Click "OK" to delete the document set or "Cancel" to return to the Document Set page.
|
||||
|
||||
_**Note:** If you delete a Document Set, the documents will still remain on the system._
|
||||
|
||||
![Example of deleting a document set](_images/delete_doc_set.png)
|
||||
|
||||
## Removing a file from a Document Set
|
||||
|
||||
To remove a file from a Document Set, navigate to the Document Set tab (either in **Documents** or from the **Page**) and open the Document Set. All documents in that set will be displayed along with an "Unlink" button. This will not delete the document, but will remove it from the Document Set.
|
||||
|
||||
![Example of deleting a document set](_images/unlink_doc_from_set.png)
|
||||
|
||||
## Deleting files from the CMS
|
||||
|
||||
To delete documents entirely from the system go to the **Documents** section, "Document" tab, and click on the delete icon on the right hand side of the document you want to delete. Similarly to deleting a Document Set, you will be asked to confirm if you want to delete the document.
|
||||
|
||||
![Example of deleting a document set](_images/delete_doc_from_system.png)
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
title: Document Management System
|
||||
summary: Using the Document Management System module in the SilverStripe CMS
|
||||
---
|
||||
|
||||
# Using the Document Management System
|
||||
|
||||
* [Introduction to DMS](introduction.md)
|
||||
* [Document set management](document-sets.md)
|
||||
* [Query Builder](query-builder.md)
|
||||
* [Setting permissions on a document](permissions.md)
|
||||
* [Document Management System Cart Module](doc-cart.md)
|
|
@ -0,0 +1,7 @@
|
|||
# Introduction
|
||||
|
||||
The Document Management System (DMS) is a way to organise related documents into sets, either through manually creating links between documents or through utilising tags and other key criteria already placed on a Document. Sets of similar documents are called Document Sets. This module provides an easy way to create, maintain and manage Document Sets as well as individual documents included in each set.
|
||||
|
||||
This guide will show you how to create a Document Set manually or by using our Query Builder tool that can create a set of multiple documents with just a few clicks.
|
||||
|
||||
Once created, Document Sets can be added to your pages to display "Related documents", providing supporting documents or relevant information.
|
|
@ -0,0 +1,47 @@
|
|||
# Setting permissions on a document
|
||||
|
||||
You can edit a document’s details and permissions inside a "Document Set" or in the **Documents** area under the "Document" tab by clicking on the document in the list. Here you will find where to change the "Title", "Description", "Cover Image", "Download behaviour" and "Actions" of your document.
|
||||
|
||||
There are various options that you can set for particular documents under the title "Actions".
|
||||
|
||||
![Example of deleting a document set](_images/actions.png)
|
||||
|
||||
**Embargo**
|
||||
|
||||
"Embargo" is where you can choose to set your content to draft then have it automatically published on a set time and date.
|
||||
|
||||
**Expiry**
|
||||
|
||||
You can also set your document to expire on a particular date under the "Expiry" tab. Expired documents will immediately stop showing up on the main website. Visitors cannot view unpublished content but you can access it in the CMS. For both "Embargo" and "Expiry" settings, simply select a date from the calendar date picker and enter the time you need.
|
||||
|
||||
**Replace**
|
||||
|
||||
The "Replace" tab allows you to replace a file using drag-and-drop or by attaching a file from your computer.
|
||||
|
||||
**Usage**
|
||||
|
||||
The "Usage" tab shows what pages the current document is used on.
|
||||
|
||||
**References**
|
||||
|
||||
The "References" tab will show you pages where the current document has been referenced in the HTML content, such as adding shortcodes to documents which direct to content.
|
||||
|
||||
**Related documents**
|
||||
|
||||
The "Related documents" tab allows you to link related documents to a document. Related documents will be displayed in a list underneath the main document when viewing the associated page on your website. This example shows "document.pdf" with its related document "example.pdf".
|
||||
|
||||
![Example of deleting a document set](_images/related_documents.png)
|
||||
|
||||
![Example of deleting a document set](_images/main_website.png)
|
||||
|
||||
_**Note:** You can link any document in the DMS to any document set. A document does not "belong" to a specific set. For example, if you upload a document to set-A, then relate it to set-B, then unlink the document from set-A, the document will stay on set-B._
|
||||
|
||||
You can set various permissions for different user groups under the "Permissions" tab such as "Who can view this document?" and "Who can edit this document?". For example, if the group "Test group" is able to view but not edit a document, the group will see a magnifying glass icon to only view uneditable information of that particular document. When viewing the main website, only users logged in and belonging to the "Test group" will be able to see the document.
|
||||
|
||||
![Example of deleting a document set](_images/permissions.png)
|
||||
|
||||
![Example of deleting a document set](_images/test_group_CMS.png)
|
||||
|
||||
**Versions**
|
||||
|
||||
The "Versions" tab shows you old versions of the document if you have previously replaced it.
|
|
@ -0,0 +1,11 @@
|
|||
# Query Builder
|
||||
|
||||
## Bulk add documents to a Document Set
|
||||
|
||||
The query builder is an easy way to add multiple, similar documents to a Document Set. To see the "Query Builder" tab, navigate to the Document Set you want.
|
||||
|
||||
![Example of deleting a document set](_images/query_builder.png)
|
||||
|
||||
Using a selection of criteria, query builder allows you to search for and automatically add relevant documents to the current set. The fields in this section are developer configurable, and may include things such as "title matches", "order by" and "tags match" (if the [taxonomy module](http://addons.silverstripe.org/add-ons/silverstripe/taxonomy) is installed).
|
||||
|
||||
Once you define query builder criteria, the results will be built when you save the document set.
|
After Width: | Height: | Size: 273 B |
|
@ -1,125 +1,135 @@
|
|||
(function($) {
|
||||
"use strict";
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
$.entwine('ss', function($) {
|
||||
$('.document-add-existing').entwine({
|
||||
adddocument: function(document_id) {
|
||||
var page_id = $(this).closest('form').find(':input[name=ID]').val();
|
||||
$.entwine('ss', function ($) {
|
||||
$('.document-add-existing').entwine({
|
||||
adddocument: function (document_id) {
|
||||
var documentSetId = $(this).closest('form').find('input[name="DSID"]').val();
|
||||
|
||||
jQuery.ajax(
|
||||
'admin/pages/adddocument/linkdocument?ID=' + page_id + '&documentID=' + document_id,
|
||||
{
|
||||
dataType: 'json',
|
||||
success: function(data, textstatus) {
|
||||
var fn = window.tmpl.cache['ss-uploadfield-addtemplate'];
|
||||
var fnout = fn({
|
||||
files: [data],
|
||||
formatFileSize: function (bytes) {
|
||||
if (typeof bytes !== 'number') return '';
|
||||
if (bytes >= 1000000000) return (bytes / 1000000000).toFixed(2) + ' GB';
|
||||
if (bytes >= 1000000) return (bytes / 1000000).toFixed(2) + ' MB';
|
||||
return (bytes / 1000).toFixed(2) + ' KB';
|
||||
}
|
||||
});
|
||||
jQuery.ajax(
|
||||
'admin/pages/adddocument/linkdocument?dsid=' + documentSetId + '&documentID=' + document_id,
|
||||
{
|
||||
dataType: 'json',
|
||||
success: function (data, textstatus) {
|
||||
var fn = window.tmpl.cache['ss-uploadfield-addtemplate'];
|
||||
var fnout = fn({
|
||||
files: [data],
|
||||
formatFileSize: function (bytes) {
|
||||
if (typeof bytes !== 'number') {
|
||||
return '';
|
||||
}
|
||||
if (bytes >= 1000000000) {
|
||||
return (bytes / 1000000000).toFixed(2) + ' GB'
|
||||
}
|
||||
if (bytes >= 1000000) {
|
||||
return (bytes / 1000000).toFixed(2) + ' MB';
|
||||
}
|
||||
return (bytes / 1000).toFixed(2) + ' KB';
|
||||
}
|
||||
});
|
||||
|
||||
$('.ss-add-files').append(fnout);
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
selectdocument: function(documentID, documentName) {
|
||||
if (typeof(documentID) !== "undefined") {
|
||||
//substitute the ID for the full document name, if no name is present
|
||||
if (typeof(documentName) === "undefined") {
|
||||
documentName = documentID;
|
||||
}
|
||||
$('.ss-add-files').html('<div class="selected-document" data-document-id="'+documentID+'">'+documentName+'</div>');
|
||||
} else {
|
||||
$('.ss-add-files').html('');
|
||||
}
|
||||
}
|
||||
});
|
||||
$('.ss-add-files').append(fnout);
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
selectdocument: function (documentID, documentName) {
|
||||
if (typeof(documentID) !== "undefined") {
|
||||
// Substitute the ID for the full document name, if no name is present
|
||||
if (typeof(documentName) === "undefined") {
|
||||
documentName = documentID;
|
||||
}
|
||||
$('.ss-add-files').html('<div class="selected-document" data-document-id="'+documentID+'">'+documentName+'</div>');
|
||||
} else {
|
||||
$('.ss-add-files').html('');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.document-add-existing .document-autocomplete').entwine({
|
||||
onmatch: function() {
|
||||
var self = this;
|
||||
this.autocomplete({
|
||||
source: 'admin/pages/adddocument/documentautocomplete',
|
||||
select: function(event, ui) {
|
||||
if(ui.item) {
|
||||
if (self.closest('.document-add-existing').hasClass('link-editor-context')) {
|
||||
$(this).closest('.document-add-existing').selectdocument(ui.item.value, ui.item.label);
|
||||
} else {
|
||||
$(this).closest('.document-add-existing').adddocument(ui.item.value);
|
||||
}
|
||||
$('.document-add-existing .document-autocomplete').entwine({
|
||||
onmatch: function () {
|
||||
var self = this;
|
||||
this.autocomplete({
|
||||
source: 'admin/pages/adddocument/documentautocomplete',
|
||||
select: function (event, ui) {
|
||||
if (ui.item) {
|
||||
if (self.closest('.document-add-existing').hasClass('link-editor-context')) {
|
||||
$(this).closest('.document-add-existing').selectdocument(ui.item.value, ui.item.label);
|
||||
} else {
|
||||
$(this).closest('.document-add-existing').adddocument(ui.item.value);
|
||||
}
|
||||
|
||||
$(this).val('');
|
||||
$(this).val('');
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add label to tree drop down button
|
||||
$('.document-add-existing .treedropdownfield-toggle-panel-link').entwine({
|
||||
onmatch: function() {
|
||||
this.prepend('<span>Browse by page</span>');
|
||||
}
|
||||
});
|
||||
// Add label to tree drop down button
|
||||
$('.document-add-existing .treedropdownfield-toggle-panel-link').entwine({
|
||||
onmatch: function () {
|
||||
this.prepend('<span>Browse by page</span>');
|
||||
}
|
||||
});
|
||||
|
||||
$('.document-add-existing .TreeDropdownField').entwine({
|
||||
onpanelshow: function() {
|
||||
$(this).closest('.document-add-existing').find('input.document-autocomplete').prop('disabled', true);
|
||||
},
|
||||
onpanelhide: function() {
|
||||
$(this).closest('.document-add-existing').find('input.document-autocomplete').prop('disabled', $(this).closest('.document-add-existing').find('.document-list:visible').length > 0);
|
||||
}
|
||||
});
|
||||
$('.document-add-existing .TreeDropdownField').entwine({
|
||||
onpanelshow: function () {
|
||||
$(this).closest('.document-add-existing').find('input.document-autocomplete').prop('disabled', true);
|
||||
},
|
||||
onpanelhide: function () {
|
||||
$(this)
|
||||
.closest('.document-add-existing')
|
||||
.find('input.document-autocomplete')
|
||||
.prop('disabled', $(this).closest('.document-add-existing').find('.document-list:visible').length > 0);
|
||||
}
|
||||
});
|
||||
|
||||
$('.document-add-existing input[name=PageSelector]').entwine({
|
||||
onchange: function(event) {
|
||||
var doclist = $(this).closest('.document-add-existing').find('.document-list');
|
||||
doclist.html('<p>Loading...</p>');
|
||||
doclist.show();
|
||||
doclist.load(
|
||||
'admin/pages/adddocument/documentlist?pageID=' + $(this).val()
|
||||
);
|
||||
|
||||
}
|
||||
});
|
||||
$('.document-add-existing input[name=PageSelector]').entwine({
|
||||
onchange: function (event) {
|
||||
var doclist = $(this).closest('.document-add-existing').find('.document-list');
|
||||
doclist.html('<p>Loading...</p>');
|
||||
doclist.show();
|
||||
doclist.load(
|
||||
'admin/pages/adddocument/documentlist?pageID=' + $(this).val()
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
$('.document-add-existing a.add-document').entwine({
|
||||
onclick: function(event) {
|
||||
var document_id = this.data('document-id');
|
||||
var dae = this.closest('.document-add-existing');
|
||||
$('.document-add-existing a.add-document').entwine({
|
||||
onclick: function (event) {
|
||||
var document_id = this.data('document-id');
|
||||
var dae = this.closest('.document-add-existing');
|
||||
|
||||
if (dae.hasClass('link-editor-context')) {
|
||||
dae.selectdocument(document_id, this.text());
|
||||
} else {
|
||||
dae.adddocument(document_id);
|
||||
}
|
||||
if (dae.hasClass('link-editor-context')) {
|
||||
dae.selectdocument(document_id, this.text());
|
||||
} else {
|
||||
dae.adddocument(document_id);
|
||||
}
|
||||
|
||||
$(this).closest('.document-list').hide();
|
||||
$(this).closest('.document-add-existing').find('input.document-autocomplete').prop('disabled', false);
|
||||
$(this).closest('.document-list').hide();
|
||||
$(this).closest('.document-add-existing').find('input.document-autocomplete').prop('disabled', false);
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$('body').entwine({
|
||||
onclick: function(event) {
|
||||
$('.document-list:visible').hide()
|
||||
.closest('.document-add-existing').find('input.document-autocomplete').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
$('body').entwine({
|
||||
onclick: function (event) {
|
||||
$('.document-list:visible')
|
||||
.hide()
|
||||
.closest('.document-add-existing')
|
||||
.find('input.document-autocomplete')
|
||||
.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
|
||||
$('.document-add-existing .treedropdownfield-toggle-panel-link').entwine({
|
||||
onclick: function(event) {
|
||||
$('.document-list:visible').hide();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}(jQuery));
|
||||
$('.document-add-existing .treedropdownfield-toggle-panel-link').entwine({
|
||||
onclick: function (event) {
|
||||
$('.document-list:visible').hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
}(jQuery));
|
||||
|
|
|
@ -1,160 +1,144 @@
|
|||
(function($) {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
$.entwine('ss', function($) {
|
||||
$.entwine('ss', function($) {
|
||||
$('#DocumentTypeID ul li').entwine({
|
||||
onadd: function () {
|
||||
this.addClass('ui-button ss-ui-button ui-corner-all ui-state-default ui-widget ui-button-text-only');
|
||||
this.parents('ul').removeClass('ui-tabs-nav');
|
||||
if (this.find('input').is(':checked')) {
|
||||
this.addClass('selected');
|
||||
}
|
||||
},
|
||||
onclick: function(e) {
|
||||
$('#DocumentTypeID').find('li.selected').removeClass('selected');
|
||||
this.find('input').prop("checked", true);
|
||||
this.addClass('selected');
|
||||
}
|
||||
});
|
||||
|
||||
$('#DocumentTypeID ul li').entwine({
|
||||
onadd: function() {
|
||||
this.addClass('ui-button ss-ui-button ui-corner-all ui-state-default ui-widget ui-button-text-only');
|
||||
this.parents('ul').removeClass('ui-tabs-nav');
|
||||
if(this.find('input').is(':checked')) this.addClass('selected');
|
||||
},
|
||||
onclick: function(e){
|
||||
$('#DocumentTypeID').find('li.selected').removeClass('selected');
|
||||
this.find('input').prop("checked", true);
|
||||
this.addClass('selected');
|
||||
}
|
||||
});
|
||||
$('.permissions input[name="CanViewType"], .permissions input[name="CanEditType"]').entwine({
|
||||
onchange: function () {
|
||||
if (!this.is(':checked')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* $('#DocumentTypeID input[type=radio]').entwine({
|
||||
onadd: function() {
|
||||
// Checks to see what radio button is selected
|
||||
if (this.is(':checked')) {
|
||||
this.change();
|
||||
}
|
||||
},
|
||||
onchange: function(e) {
|
||||
// Remove selected class from radio buttons
|
||||
$('#DocumentTypeID').find('li').removeClass('selected');
|
||||
//If radio button is checked then add the selected class
|
||||
if (this.is(':checked')) {
|
||||
this.parent('li').addClass('selected');
|
||||
}
|
||||
}
|
||||
});*/
|
||||
var dropDown = this.closest('.fieldholder-small').next();
|
||||
if (this.val() === 'OnlyTheseUsers') {
|
||||
dropDown.removeClass('hide');
|
||||
} else {
|
||||
dropDown.addClass('hide');
|
||||
}
|
||||
},
|
||||
onadd: function () {
|
||||
this.trigger('change');
|
||||
}
|
||||
});
|
||||
|
||||
$('#Actions ul li').entwine({
|
||||
onclick: function(e) {
|
||||
$('.dmsdocment-actions ul li').entwine({
|
||||
onclick: function (e) {
|
||||
// Add active state to the current button
|
||||
$('.dmsdocment-actions ul li').removeClass('dms-active');
|
||||
this.addClass('dms-active');
|
||||
|
||||
//add active state to the current button
|
||||
$('#Actions ul li').removeClass('dms-active');
|
||||
this.addClass('dms-active');
|
||||
//$('li.dms-active').append('<span class="arrow"></span>');
|
||||
// Hide all inner field sections
|
||||
var panel = $('.dmsdocument-actionspanel:first');
|
||||
panel.find('> .fieldgroup > .fieldgroup-field').hide();
|
||||
|
||||
//hide all inner field sections
|
||||
var panel = $('.DMSDocumentActionsPanel:first');
|
||||
panel.find('> .fieldgroup > .fieldgroup-field').hide();
|
||||
// Show the correct group of controls
|
||||
panel.find('.'+this.data('panel')).show().parents('.fieldgroup-field').show();
|
||||
}
|
||||
});
|
||||
|
||||
//show the correct group of controls
|
||||
//panel.find('.'+this.data('panel')).closest('div.fieldgroup').show();
|
||||
panel.find('.'+this.data('panel')).show().parents('.fieldgroup-field').show();
|
||||
$('#Form_ItemEditForm_Embargo input, #Form_EditForm_Embargo input').entwine({
|
||||
onchange: function () {
|
||||
// Selected the date options
|
||||
if (this.attr('value') === 'Date') {
|
||||
$('.embargoDatetime').children().show();
|
||||
$('.embargoDatetime').show();
|
||||
} else {
|
||||
$('.embargoDatetime').hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
$('#Form_ItemEditForm_Expiry input, #Form_EditForm_Expiry input').entwine({
|
||||
onchange: function () {
|
||||
// Selected the date options
|
||||
if (this.attr('value') === 'Date') {
|
||||
$('.expiryDatetime').children().show();
|
||||
$('.expiryDatetime').show();
|
||||
} else {
|
||||
$('.expiryDatetime').hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#Form_ItemEditForm_Embargo input, #Form_EditForm_Embargo input').entwine({
|
||||
onchange: function() {
|
||||
console.log('called');
|
||||
//selected the date options
|
||||
if (this.attr('value') === 'Date') {
|
||||
$('.embargoDatetime').children().show();
|
||||
$('.embargoDatetime').show();
|
||||
} else {
|
||||
$('.embargoDatetime').hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
$('.dmsdocument-actionspanel').entwine({
|
||||
onadd: function () {
|
||||
// Do an initial show of the entire panel
|
||||
this.show();
|
||||
|
||||
$('#Form_ItemEditForm_Expiry input, #Form_EditForm_Expiry input').entwine({
|
||||
onchange: function() {
|
||||
//selected the date options
|
||||
if (this.attr('value') === 'Date') {
|
||||
$('.expiryDatetime').children().show();
|
||||
$('.expiryDatetime').show();
|
||||
} else {
|
||||
$('.expiryDatetime').hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
// Add some extra classes to the replace field containers to make it work with drag and drop uploading
|
||||
this.find('.replace').closest('div.fieldgroup-field').addClass('ss-upload').addClass('ss-uploadfield');
|
||||
|
||||
$('.DMSDocumentActionsPanel').entwine({
|
||||
onadd: function() {
|
||||
//do an initial show of the entire panel
|
||||
this.show();
|
||||
// Add class and hide
|
||||
$('.dmsdocument-actionspanel .embargo input.date').closest('.fieldholder-small').addClass('embargoDatetime').hide();
|
||||
$('.dmsdocument-actionspanel .expiry input.date').closest('.fieldholder-small').addClass('expiryDatetime').hide();
|
||||
|
||||
//add some extra classes to the replace field containers to make it work with drag and drop uploading
|
||||
this.find('.replace').closest('div.fieldgroup-field').addClass('ss-upload').addClass('ss-uploadfield');
|
||||
|
||||
// add class and hide
|
||||
$('.DMSDocumentActionsPanel .embargo input.date').closest('.fieldholder-small').addClass('embargoDatetime').hide();
|
||||
$('.DMSDocumentActionsPanel .expiry input.date').closest('.fieldholder-small').addClass('expiryDatetime').hide();
|
||||
// We need to duplicate the above functions to work when Adding documents
|
||||
// $('#Form_EditForm_EmbargoedUntilDate_date').closest('.fieldholder-small').addClass('embargoDatetime').hide();
|
||||
// $('#Form_EditForm_ExpireAtDate_date').closest('.fieldholder-small').addClass('expiryDatetime').hide();
|
||||
// Add placeholder attribute to date and time fields
|
||||
$('.dmsdocument-actionspanel .embargo input.date').attr('placeholder', 'dd-mm-yyyy');
|
||||
$('.dmsdocument-actionspanel .embargo input.time').attr('placeholder', 'hh:mm:ss');
|
||||
$('.dmsdocument-actionspanel .expiry input.date').attr('placeholder', 'dd-mm-yyyy');
|
||||
$('.dmsdocument-actionspanel .expiry input.time').attr('placeholder', 'hh:mm:ss');
|
||||
|
||||
//Add placeholder attribute to date and time fields
|
||||
$('.DMSDocumentActionsPanel .embargo input.date').attr('placeholder', 'dd-mm-yyyy');
|
||||
$('.DMSDocumentActionsPanel .embargo input.time').attr('placeholder', 'hh:mm:ss');
|
||||
$('.DMSDocumentActionsPanel .expiry input.date').attr('placeholder', 'dd-mm-yyyy');
|
||||
$('.DMSDocumentActionsPanel .expiry input.time').attr('placeholder', 'hh:mm:ss');
|
||||
// We need to duplicate to work when adding documents
|
||||
// $('#Form_EditForm_EmbargoedUntilDate_date').attr('placeholder', 'dd-mm-yyyy');
|
||||
// $('#Form_EditForm_EmbargoedUntilDate_time').attr('placeholder', 'hh:mm:ss');
|
||||
// $('#Form_EditForm_ExpireAtDate_date').attr('placeholder', 'dd-mm-yyyy');
|
||||
// $('#Form_EditForm_ExpireAtDate_time').attr('placeholder', 'hh:mm:ss');
|
||||
// Show the embargo panel when the page loads
|
||||
$('li[data-panel="embargo"]').click();
|
||||
|
||||
//show the embargo panel when the page loads
|
||||
$('li[data-panel="embargo"]').click();
|
||||
// Set the initial state of the radio button and the associated dropdown hiding
|
||||
$('.dmsdocument-actionspanel .embargo input[type="radio"][checked]').change();
|
||||
$('.dmsdocument-actionspanel .expiry input[type="radio"][checked]').change();
|
||||
}
|
||||
});
|
||||
|
||||
//set the initial state of the radio button and the associated dropdown hiding
|
||||
$('.DMSDocumentActionsPanel .embargo input[type="radio"][checked]').change();
|
||||
$('.DMSDocumentActionsPanel .expiry input[type="radio"][checked]').change();
|
||||
//Again we need to duplicate the above function to work when adding documents
|
||||
// $('#Form_EditForm_Embargo input[checked]').change();
|
||||
// $('#Form_EditForm_Expiry input[checked]').change();
|
||||
}
|
||||
});
|
||||
$('#Form_ItemEditForm_action_doDelete').entwine({
|
||||
onclick: function (e) {
|
||||
// Work out how many pages are left attached to this document
|
||||
var form = this.closest('form');
|
||||
var pagesCount = form.data('pages-count');
|
||||
var relationCount = form.data('relation-count');
|
||||
|
||||
$('#Form_ItemEditForm_action_doDelete').entwine({
|
||||
onclick: function(e){
|
||||
//work out how many pages are left attached to this document
|
||||
var form = this.closest('form');
|
||||
var pagesCount = form.data('pages-count');
|
||||
var relationCount = form.data('relation-count');
|
||||
// Display an appropriate message
|
||||
var message = '';
|
||||
if (pagesCount > 1 || relationCount > 0) {
|
||||
var pages = '';
|
||||
if (pagesCount > 1) {
|
||||
pages = "\nWarning: doc is attached to a total of "+pagesCount+" pages. ";
|
||||
}
|
||||
var references = '';
|
||||
var referencesWarning = '';
|
||||
if (relationCount > 0) {
|
||||
var pname = 'pages';
|
||||
referencesWarning = "\n\nBefore deleting: please update the content on the pages where this document is referenced, otherwise the links on those pages will break.";
|
||||
if (relationCount === 1) {
|
||||
pname = 'page';
|
||||
referencesWarning = "\n\nBefore deleting: please update the content on the page where this document is referenced, otherwise the links on that page will break.";
|
||||
}
|
||||
references = "\nWarning: doc is referenced in the text of "+relationCount +" "+pname+".";
|
||||
}
|
||||
message = "Permanently delete this document and remove it from all pages where it is referenced?\n"+pages+references+"\n\nDeleting it here will permanently delete it from this page and all other pages where it is referenced."+referencesWarning;
|
||||
} else {
|
||||
message = "Permanently delete this document and remove it from this page?\n\nNotice: this document is only attached to this page, so deleting it won't affect any other pages.";
|
||||
}
|
||||
|
||||
//display an appropriate message
|
||||
var message = '';
|
||||
if (pagesCount > 1 || relationCount > 0) {
|
||||
var pages = '';
|
||||
if (pagesCount > 1) {
|
||||
pages = "\nWarning: doc is attached to a total of "+pagesCount+" pages. ";
|
||||
}
|
||||
var references = '';
|
||||
var referencesWarning = '';
|
||||
if (relationCount > 0) {
|
||||
var pname = 'pages';
|
||||
referencesWarning = "\n\nBefore deleting: please update the content on the pages where this document is referenced, otherwise the links on those pages will break.";
|
||||
if (relationCount === 1) {
|
||||
pname = 'page';
|
||||
referencesWarning = "\n\nBefore deleting: please update the content on the page where this document is referenced, otherwise the links on that page will break.";
|
||||
}
|
||||
references = "\nWarning: doc is referenced in the text of "+relationCount +" "+pname+".";
|
||||
}
|
||||
message = "Permanently delete this document and remove it from all pages where it is referenced?\n"+pages+references+"\n\nDeleting it here will permanently delete it from this page and all other pages where it is referenced."+referencesWarning;
|
||||
} else {
|
||||
message = "Permanently delete this document and remove it from this page?\n\nNotice: this document is only attached to this page, so deleting it won't affect any other pages.";
|
||||
}
|
||||
|
||||
if(!confirm(message)) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
} else {
|
||||
//user says "okay", so go ahead and do the action
|
||||
this._super(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}(jQuery));
|
||||
if (!confirm(message)) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
} else {
|
||||
// User says "okay", so go ahead and do the action
|
||||
this._super(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}(jQuery));
|
||||
|
|
|
@ -1,125 +1,24 @@
|
|||
(function($){
|
||||
"use strict";
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
$.entwine('ss', function($) {
|
||||
$.entwine('ss', function ($) {
|
||||
$('.ss-gridfield-item a.file-url').entwine({
|
||||
onclick: function (e) {
|
||||
// Make sure the download link doesn't trigger a gridfield edit dialog
|
||||
window.open(this.attr('href'), '_blank');
|
||||
|
||||
$('#SectionID ul li').entwine({
|
||||
onadd: function() {
|
||||
this.addClass('ui-button ss-ui-button ui-corner-all ui-state-default ui-widget ui-button-text-only');
|
||||
this.parents('ul').removeClass('ui-tabs-nav');
|
||||
}
|
||||
});
|
||||
|
||||
$('#SectionID input[type=radio]').entwine({
|
||||
onadd: function() {
|
||||
// Checks to see what radio button is selected
|
||||
if (this.is(':checked')) {
|
||||
this.change();
|
||||
}
|
||||
},
|
||||
onchange: function(e) {
|
||||
// Remove selected class from radio buttons
|
||||
$('#SectionID').find('li').removeClass('selected');
|
||||
//If radio button is checked then add the selected class
|
||||
if (this.is(':checked')) {
|
||||
this.parent('li').addClass('selected');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.ss-gridfield .action.dms-delete').entwine({
|
||||
onclick: function(e){
|
||||
//work out how many pages are left attached to this document
|
||||
var pagesCount = this.data('pages-count');
|
||||
var pagesCountAfterDeletion = pagesCount - 1;
|
||||
var addS = 's';
|
||||
if (pagesCountAfterDeletion === 1) {
|
||||
addS = '';
|
||||
}
|
||||
|
||||
//display an appropriate message
|
||||
var message = '';
|
||||
if (this.hasClass('dms-delete-last-warning')) {
|
||||
message = "Permanently delete this document?\n\nWarning: this document is attached only to this page, deleting it here will delete it permanently.";
|
||||
}
|
||||
if (this.hasClass('dms-delete-link-only')) {
|
||||
message = "Unlink this document from this page?\n\nNote: it will remain attached to "+pagesCountAfterDeletion+" other page"+addS+".";
|
||||
}
|
||||
|
||||
if(!confirm(message)) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
} else {
|
||||
//user says "okay", so go ahead and do the action
|
||||
this._super(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.ss-gridfield .dms-document-hidden').entwine({
|
||||
onadd: function() {
|
||||
this.closest('tr').addClass('dms-document-hidden-row');
|
||||
}
|
||||
});
|
||||
|
||||
$('.cms-content-actions.south .ss-ui-action-destructive').entwine({
|
||||
confirmBeforeDelete: function() {
|
||||
var deleteButtons = $('button.dms-delete[data-pages-count=1]');
|
||||
|
||||
//we have page with DMSDocuments on it, and we have documents that only exist on this page
|
||||
if (deleteButtons.length > 0) {
|
||||
var message = "Are you sure you want to delete this page? Deleting this page will delete "+deleteButtons.length;
|
||||
if (deleteButtons.length === 1) {
|
||||
message += " document that is associated only with this page. This document is:\n\n";
|
||||
} else {
|
||||
message += " documents that are associated only with this page. These documents are:\n\n";
|
||||
}
|
||||
|
||||
//create a list of documents and their IDs
|
||||
deleteButtons.each(function(){
|
||||
var tr = $(this).closest('tr');
|
||||
message += tr.find('.col-ID').text() +' - '+ tr.find('.col-Title').text() +"\n";
|
||||
});
|
||||
|
||||
if(!confirm(message)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
$('#Form_EditForm_action_deletefromlive').entwine({
|
||||
onclick: function(e) {
|
||||
if (this.confirmBeforeDelete()) {
|
||||
this._super(e);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#Form_EditForm_action_delete').entwine({
|
||||
onclick: function(e) {
|
||||
if (this.confirmBeforeDelete()) {
|
||||
this._super(e);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('.ss-gridfield-item a.file-url').entwine({
|
||||
onclick: function(e) {
|
||||
//make sure the download link doesn't trigger a gridfield edit dialog
|
||||
window.open(this.attr('href'), '_blank');
|
||||
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$('.ss-gridfield-item a.dms-doc-sets-link').entwine({
|
||||
onclick: function (e){
|
||||
// Prevent the initial flash of the gridfield's edit form
|
||||
e.preventDefault();
|
||||
document.location.href=this.attr('href');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}(jQuery));
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
window.tmpl.cache['ss-uploadfield-addtemplate'] = tmpl(
|
||||
'{% for (var i=0, files=o.files, l=files.length, file=files[0]; i<l; file=files[++i]) { %}' +
|
||||
'<li class="ss-uploadfield-item template-download{% if (file.error) { %} ui-state-error{% } %}" data-fileid="{%=file.id%}">' +
|
||||
'<div class="ss-uploadfield-item-preview preview"><span>' +
|
||||
'<img src="{%=file.thumbnail_url%}" alt="" />' +
|
||||
'</span></div>' +
|
||||
'<div class="ss-uploadfield-item-info">' +
|
||||
'<label class="ss-uploadfield-item-name">' +
|
||||
'<span class="name" title="{%=file.name%}">{%=file.name%}</span> ' +
|
||||
'{% if (!file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-status ui-state-success-text" title="'+ss.i18n._t('UploadField.AddedToPage', 'Added to Page')+'">'+ss.i18n._t('UploadField.AddedToPage', 'Added to Page')+'</div>' +
|
||||
'{% } else { %}' +
|
||||
'<div class="ss-uploadfield-item-status ui-state-error-text" title="{%=o.options.errorMessages[file.error] || file.error%}">{%=o.options.errorMessages[file.error] || file.error%}</div>' +
|
||||
'{% } %}' +
|
||||
'<div class="clear"><!-- --></div>' +
|
||||
'</label>' +
|
||||
'{% if (file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-actions">' +
|
||||
'<div class="ss-uploadfield-item-cancel ss-uploadfield-item-cancelfailed"><button class="icon icon-16">' + ss.i18n._t('UploadField.CANCEL', 'Cancel') + '</button></div>' +
|
||||
'</div>' +
|
||||
'{% } else { %}' +
|
||||
'<div class="ss-uploadfield-item-actions">{% print(file.buttons, true); %}</div>' +
|
||||
'{% } %}' +
|
||||
'</div>' +
|
||||
'{% if (!file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-editform loading"><iframe frameborder="0" src="{%=file.edit_url%}"></iframe></div>' +
|
||||
'{% } %}' +
|
||||
'</li>' +
|
||||
'{% } %}'
|
||||
);
|
||||
'{% for (var i=0, files=o.files, l=files.length, file=files[0]; i<l; file=files[++i]) { %}' +
|
||||
'<li class="ss-uploadfield-item template-download{% if (file.error) { %} ui-state-error{% } %}" data-fileid="{%=file.id%}">' +
|
||||
'<div class="ss-uploadfield-item-preview preview"><span>' +
|
||||
'<img src="{%=file.thumbnail_url%}" alt="" />' +
|
||||
'</span></div>' +
|
||||
'<div class="ss-uploadfield-item-info">' +
|
||||
'<label class="ss-uploadfield-item-name">' +
|
||||
'<span class="name" title="{%=file.name%}">{%=file.name%}</span> ' +
|
||||
'{% if (!file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-status ui-state-success-text" title="'+ss.i18n._t('UploadField.AddedToDocumentSet', 'Added to Document Set')+'">'+ss.i18n._t('UploadField.AddedToDocumentSet', 'Added to Document Set')+'</div>' +
|
||||
'{% } else { %}' +
|
||||
'<div class="ss-uploadfield-item-status ui-state-error-text" title="{%=o.options.errorMessages[file.error] || file.error%}">{%=o.options.errorMessages[file.error] || file.error%}</div>' +
|
||||
'{% } %}' +
|
||||
'<div class="clear"><!-- --></div>' +
|
||||
'</label>' +
|
||||
'{% if (file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-actions">' +
|
||||
'<div class="ss-uploadfield-item-cancel ss-uploadfield-item-cancelfailed"><button class="icon icon-16">' + ss.i18n._t('UploadField.CANCEL', 'Cancel') + '</button></div>' +
|
||||
'</div>' +
|
||||
'{% } else { %}' +
|
||||
'<div class="ss-uploadfield-item-actions">{% print(file.buttons, true); %}</div>' +
|
||||
'{% } %}' +
|
||||
'</div>' +
|
||||
'{% if (!file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-editform loading"><iframe frameborder="0" src="{%=file.edit_url%}"></iframe></div>' +
|
||||
'{% } %}' +
|
||||
'</li>' +
|
||||
'{% } %}'
|
||||
);
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
window.tmpl.cache['ss-dmsuploadfield-downloadtemplate'] = tmpl(
|
||||
'{% for (var i=0, files=o.files, l=files.length, file=files[0]; i<l; file=files[++i]) { %}' +
|
||||
'<li class="ss-uploadfield-item template-download{% if (file.error) { %} ui-state-error{% } %}" data-fileid="{%=file.id%}">' +
|
||||
'<div class="ss-uploadfield-item-preview preview"><span>' +
|
||||
'<img src="{%=file.thumbnail_url%}" alt="" />' +
|
||||
'</span></div>' +
|
||||
'<div class="ss-uploadfield-item-info">' +
|
||||
'<label class="ss-uploadfield-item-name">' +
|
||||
'<span class="name" title="{%=file.name%}">{%=file.name%}</span> ' +
|
||||
'{% if (!file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-status ui-state-success-text" title="'+ss.i18n._t('UploadField.Uploaded', 'Uploaded')+'">'+ss.i18n._t('UploadField.Uploaded', 'Uploaded')+'</div>' +
|
||||
'{% } else { %}' +
|
||||
'<div class="ss-uploadfield-item-status ui-state-error-text" title="{%=o.options.errorMessages[file.error] || file.error%}">{%=o.options.errorMessages[file.error] || file.error%}</div>' +
|
||||
'{% } %}' +
|
||||
'<div class="clear"><!-- --></div>' +
|
||||
'</label>' +
|
||||
'{% if (file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-actions">' +
|
||||
'<div class="ss-uploadfield-item-cancel ss-uploadfield-item-cancelfailed"><button class="icon icon-16">' + ss.i18n._t('UploadField.CANCEL', 'Cancel') + '</button></div>' +
|
||||
'</div>' +
|
||||
'{% } else { %}' +
|
||||
'<div class="ss-uploadfield-item-actions">(please click save and the page will update)</div>' +
|
||||
'{% } %}' +
|
||||
'</div>' +
|
||||
'</li>' +
|
||||
'{% } %}'
|
||||
);
|
||||
'{% for (var i=0, files=o.files, l=files.length, file=files[0]; i<l; file=files[++i]) { %}' +
|
||||
'<li class="ss-uploadfield-item template-download{% if (file.error) { %} ui-state-error{% } %}" data-fileid="{%=file.id%}">' +
|
||||
'<div class="ss-uploadfield-item-preview preview"><span>' +
|
||||
'<img src="{%=file.thumbnail_url%}" alt="" />' +
|
||||
'</span></div>' +
|
||||
'<div class="ss-uploadfield-item-info">' +
|
||||
'<label class="ss-uploadfield-item-name">' +
|
||||
'<span class="name" title="{%=file.name%}">{%=file.name%}</span> ' +
|
||||
'{% if (!file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-status ui-state-success-text" title="'+ss.i18n._t('UploadField.Uploaded', 'Uploaded')+'">'+ss.i18n._t('UploadField.Uploaded', 'Uploaded')+'</div>' +
|
||||
'{% } else { %}' +
|
||||
'<div class="ss-uploadfield-item-status ui-state-error-text" title="{%=o.options.errorMessages[file.error] || file.error%}">{%=o.options.errorMessages[file.error] || file.error%}</div>' +
|
||||
'{% } %}' +
|
||||
'<div class="clear"><!-- --></div>' +
|
||||
'</label>' +
|
||||
'{% if (file.error) { %}' +
|
||||
'<div class="ss-uploadfield-item-actions">' +
|
||||
'<div class="ss-uploadfield-item-cancel ss-uploadfield-item-cancelfailed"><button class="icon icon-16">' + ss.i18n._t('UploadField.CANCEL', 'Cancel') + '</button></div>' +
|
||||
'</div>' +
|
||||
'{% } else { %}' +
|
||||
'<div class="ss-uploadfield-item-actions">(please click save and the page will update)</div>' +
|
||||
'{% } %}' +
|
||||
'</div>' +
|
||||
'</li>' +
|
||||
'{% } %}'
|
||||
);
|
||||
|
|
|
@ -1,108 +1,118 @@
|
|||
(function($) {
|
||||
"use strict";
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
$.entwine('ss', function($) {
|
||||
$.entwine('ss', function ($) {
|
||||
$('form.htmleditorfield-linkform input[name=LinkType]').entwine({
|
||||
onchange: function (e) {
|
||||
this._super(e);
|
||||
|
||||
$('form.htmleditorfield-linkform input[name=LinkType]').entwine({
|
||||
onchange: function(e) {
|
||||
this._super(e);
|
||||
var form = $('form.htmleditorfield-linkform');
|
||||
var show = false;
|
||||
|
||||
var form = $('form.htmleditorfield-linkform');
|
||||
var show = false;
|
||||
if (this.attr('value') === 'document') {
|
||||
if (this.is(':checked')) {
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.attr('value') === 'document') {
|
||||
if (this.is(':checked')) {
|
||||
show = true;
|
||||
}
|
||||
}
|
||||
// Hide or show the additional document link addition tool
|
||||
if (show) {
|
||||
form.find('.ss-add').show();
|
||||
} else {
|
||||
form.find('.ss-add').hide();
|
||||
}
|
||||
},
|
||||
onadd: function (e) {
|
||||
this.change();
|
||||
}
|
||||
});
|
||||
|
||||
//hide or show the additional document link addition tool
|
||||
if (show) {
|
||||
form.find('.ss-add').show();
|
||||
} else {
|
||||
form.find('.ss-add').hide();
|
||||
}
|
||||
},
|
||||
onadd: function(e){
|
||||
this.change();
|
||||
}
|
||||
});
|
||||
$('form.htmleditorfield-linkform').entwine({
|
||||
getShortcodeKey: function () {
|
||||
return this.find(':input[name=DMSShortcodeHandlerKey]').val();
|
||||
},
|
||||
insertLink: function () {
|
||||
var href, target = null;
|
||||
var checkedValue = this.find(':input[name=LinkType]:checked').val();
|
||||
if (checkedValue === 'document') {
|
||||
href = '[' + this.getShortcodeKey() + ',id=' + this.find('.selected-document').data('document-id') + ']';
|
||||
|
||||
$('form.htmleditorfield-linkform').entwine({
|
||||
insertLink: function() {
|
||||
var href, target = null;
|
||||
var checkedValue = this.find(':input[name=LinkType]:checked').val();
|
||||
if (checkedValue === 'document') {
|
||||
href = '[dms_document_link,id=' + this.find('.selected-document').data('document-id') + ']';
|
||||
// Determine target
|
||||
if (this.find(':input[name=TargetBlank]').is(':checked')) {
|
||||
target = '_blank';
|
||||
}
|
||||
|
||||
// Determine target
|
||||
if(this.find(':input[name=TargetBlank]').is(':checked')) target = '_blank';
|
||||
var attributes = {
|
||||
href: href,
|
||||
target: target,
|
||||
class: 'documentLink',
|
||||
// Title is the text of the selected document
|
||||
title: this.find('.selected-document').text()
|
||||
};
|
||||
|
||||
var attributes = {
|
||||
href : href,
|
||||
target : target,
|
||||
class : 'documentLink',
|
||||
title : this.find('.selected-document').text() //title is the text of the selected document
|
||||
};
|
||||
this.modifySelection(function (ed) {
|
||||
ed.insertLink(attributes);
|
||||
});
|
||||
|
||||
this.modifySelection(function(ed){
|
||||
ed.insertLink(attributes);
|
||||
});
|
||||
this.updateFromEditor();
|
||||
return false;
|
||||
} else {
|
||||
this._super();
|
||||
}
|
||||
},
|
||||
getCurrentLink: function () {
|
||||
var selectedEl = this.getSelection(), href = "", target = "", title = "", action = "insert", style_class = "";
|
||||
var linkDataSource = null;
|
||||
if (selectedEl.length) {
|
||||
if (selectedEl.is('a')) {
|
||||
linkDataSource = selectedEl;
|
||||
} else {
|
||||
linkDataSource = selectedEl = selectedEl.parents('a:first');
|
||||
}
|
||||
}
|
||||
|
||||
this.updateFromEditor();
|
||||
return false;
|
||||
} else {
|
||||
this._super();
|
||||
}
|
||||
},
|
||||
getCurrentLink: function() {
|
||||
var selectedEl = this.getSelection(), href = "", target = "", title = "", action = "insert", style_class = "";
|
||||
var linkDataSource = null;
|
||||
if(selectedEl.length) {
|
||||
if(selectedEl.is('a')) {
|
||||
linkDataSource = selectedEl;
|
||||
} else {
|
||||
linkDataSource = selectedEl = selectedEl.parents('a:first');
|
||||
}
|
||||
}
|
||||
if(linkDataSource && linkDataSource.length) this.modifySelection(function(ed){
|
||||
ed.selectNode(linkDataSource[0]);
|
||||
});
|
||||
if (linkDataSource && linkDataSource.length) {
|
||||
this.modifySelection(function (ed) {
|
||||
ed.selectNode(linkDataSource[0]);
|
||||
});
|
||||
}
|
||||
|
||||
// Is anchor not a link
|
||||
if (!linkDataSource.attr('href')) linkDataSource = null;
|
||||
// Is anchor not a link
|
||||
if (!linkDataSource.attr('href')) {
|
||||
linkDataSource = null;
|
||||
}
|
||||
|
||||
if (linkDataSource) {
|
||||
href = linkDataSource.attr('href');
|
||||
target = linkDataSource.attr('target');
|
||||
title = linkDataSource.attr('title');
|
||||
style_class = linkDataSource.attr('class');
|
||||
href = this.getEditor().cleanLink(href, linkDataSource);
|
||||
action = "update";
|
||||
}
|
||||
if (linkDataSource) {
|
||||
href = linkDataSource.attr('href');
|
||||
target = linkDataSource.attr('target');
|
||||
title = linkDataSource.attr('title');
|
||||
style_class = linkDataSource.attr('class');
|
||||
href = this.getEditor().cleanLink(href, linkDataSource);
|
||||
action = "update";
|
||||
}
|
||||
|
||||
//match a document or call the regular link handling
|
||||
if(href.match(/^\[dms_document_link(\s*|%20|,)?id=([0-9]+)\]?$/i)) {
|
||||
var returnArray = {
|
||||
LinkType: 'document',
|
||||
DocumentID: RegExp.$2,
|
||||
Description: title
|
||||
};
|
||||
// Match a document or call the regular link handling
|
||||
if (href.match(new RegExp('^\\[' + this.getShortcodeKey() + '(\s*|%20|,)?id=([0-9]+)\\]?$', 'i'))) {
|
||||
var returnArray = {
|
||||
LinkType: 'document',
|
||||
DocumentID: RegExp.$2,
|
||||
Description: title
|
||||
};
|
||||
|
||||
//show the selected document
|
||||
$('.document-add-existing').selectdocument(returnArray.DocumentID,returnArray.Description);
|
||||
// Show the selected document
|
||||
$('.document-add-existing').selectdocument(returnArray.DocumentID,returnArray.Description);
|
||||
|
||||
//select the correct radio button
|
||||
$('form.htmleditorfield-linkform input[name=LinkType][value=document]').click();
|
||||
|
||||
return returnArray;
|
||||
} else {
|
||||
$('.document-add-existing').selectdocument(); //clear the selected document
|
||||
$('form.htmleditorfield-linkform .ss-add.ss-upload').hide();
|
||||
return this._super();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
// Select the correct radio button
|
||||
$('form.htmleditorfield-linkform input[name=LinkType][value=document]').click();
|
||||
|
||||
return returnArray;
|
||||
} else {
|
||||
// Clear the selected document
|
||||
$('.document-add-existing').selectdocument();
|
||||
$('form.htmleditorfield-linkform .ss-add.ss-upload').hide();
|
||||
return this._super();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}(jQuery));
|
||||
|
|
41
lang/en.yml
|
@ -9,14 +9,34 @@ en:
|
|||
TYPE: 'File type'
|
||||
URL: URL
|
||||
DMSDocument:
|
||||
COVERIMAGE: Cover Image
|
||||
DESCRIPTION: Description
|
||||
EDIT: Edit
|
||||
EDITDOCUMENT: Edit this document
|
||||
PLURALNAME: Documents
|
||||
RelatedPages: 'Related Pages'
|
||||
RelatedReferences: 'Related References'
|
||||
SINGULARNAME: Document
|
||||
Versions: Versions
|
||||
DMSTag:
|
||||
PLURALNAME: 'D M S Tags'
|
||||
SINGULARNAME: 'D M S Tag'
|
||||
DOWNLOAD: "Download {title}"
|
||||
LASTCHANGED: "Last changed: {date}"
|
||||
TITLE: Title
|
||||
DMSDocumentSet:
|
||||
ADDDOCUMENTBUTTON: Add Document
|
||||
ADDDOCUMENTSBUTTON: Add Documents
|
||||
DIRECTION_ASCENDING: Ascending
|
||||
DIRECTION_DESCENDING: Descending
|
||||
GRIDFIELD_NOTICE: Managing documents will be available once you have created this document set.
|
||||
PLURALNAME: Document Sets
|
||||
QUERY_BUILDER_NOTICE: The query builder provides the ability to add documents to a document set based on the filters below. Please note that the set will be built using this criteria when you save the form. This set will not be dynamically updated (see the documentation for more information).
|
||||
SHOWONPAGE: Show on page
|
||||
SINGULARNAME: Document Set
|
||||
TAGS_RIGHT_TITLE: Tags can be set in the taxonomy area, and can be assigned when editing a document.
|
||||
DMSSiteTreeExtension:
|
||||
DocumentSetsTabTitle: 'Document Sets ({count})'
|
||||
DMSDocumentTaxonomyExtension:
|
||||
TAGS: Tags
|
||||
NOTAGS: No tags found
|
||||
FileIFrameField:
|
||||
ATTACHONCESAVED2: 'Files can be attached once you have saved the record for the first time.'
|
||||
GridAction:
|
||||
|
@ -27,14 +47,25 @@ en:
|
|||
DeletePermissionsFailure: 'No delete permissions'
|
||||
UploadField:
|
||||
ATTACHFILE: 'Attach a file'
|
||||
DONE: Done!
|
||||
DROPFILE: 'drop a file'
|
||||
FIELDNOTSET: 'File information not found'
|
||||
FROMCMS: From the CMS
|
||||
FROMCOMPUTER: 'From your computer'
|
||||
FROMCOMPUTERINFO: 'Upload from your computer'
|
||||
MAXNUMBEROFFILES: 'Max number of {count} file(s) exceeded.'
|
||||
DMSDocumentAddController:
|
||||
MENUTITLE: 'Edit Page'
|
||||
NODOCUMENTS: 'There are no documents attached to the selected page.'
|
||||
RELATEDDOCUMENTS: 'Related Documents'
|
||||
MAINTAB: Main
|
||||
DMSDocument_versions:
|
||||
PLURALNAME: 'D M S Document_versionss'
|
||||
SINGULARNAME: 'D M S Document_versions'
|
||||
PLURALNAME: 'DMS Document_versionss'
|
||||
SINGULARNAME: 'DMS Document_versions'
|
||||
DMSDocumentAddExistingField:
|
||||
ADDEXISTING: Add Existing
|
||||
AUTOCOMPLETE: Search by ID or filename
|
||||
CHOOSESET: Choose Document Set
|
||||
EDITDOCUMENTDETAILS: Edit Document Details
|
||||
LINKADOCUMENT: Link a Document
|
||||
SELECTED: Selected Document
|
||||
|
|
|
@ -13,9 +13,6 @@ es:
|
|||
RelatedPages: 'Páginas relacionadas'
|
||||
RelatedReferences: 'Referencias relacionadas'
|
||||
SINGULARNAME: Documento
|
||||
DMSTag:
|
||||
PLURALNAME: 'Etiquetas del Sistema documental'
|
||||
SINGULARNAME: 'Etiqueta del Sistema documental'
|
||||
FileIFrameField:
|
||||
ATTACHONCESAVED2: 'Archivos pueden ser adjuntados una vez que guardes por primera vez.'
|
||||
GridAction:
|
||||
|
|
|
@ -13,9 +13,6 @@ nl:
|
|||
RelatedPages: 'Gerelateerde paginas'
|
||||
RelatedReferences: 'Gerelateerde referenties'
|
||||
SINGULARNAME: 'Document'
|
||||
DMSTag:
|
||||
PLURALNAME: 'D M S Tags'
|
||||
SINGULARNAME: 'D M S Tag'
|
||||
FileIFrameField:
|
||||
ATTACHONCESAVED2: 'Bestanden kunnen worden toegevoegd na het voor het eerst opslaan'
|
||||
GridAction:
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "silverstripe-dms",
|
||||
"version": "2.0.0",
|
||||
"description": "SilverStripe Document Management System",
|
||||
"directories": {
|
||||
"doc": "docs",
|
||||
"test": "tests"
|
||||
},
|
||||
"devDependencies": {
|
||||
"css-loader": "^0.28.1",
|
||||
"extract-text-webpack-plugin": "^2.1.0",
|
||||
"file-loader": "^0.11.1",
|
||||
"node-sass": "^4.13.1",
|
||||
"sass-loader": "^6.0.3",
|
||||
"style-loader": "^0.17.0",
|
||||
"webpack": "^2.5.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --bail --progress",
|
||||
"watch": "webpack --watch --progress"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/silverstripe/silverstripe-dms.git"
|
||||
},
|
||||
"keywords": [
|
||||
"silverstripe",
|
||||
"dms"
|
||||
],
|
||||
"author": "SilverStripe Ltd",
|
||||
"license": "BSD-3-Clause",
|
||||
"bugs": {
|
||||
"url": "https://github.com/silverstripe/silverstripe-dms/issues"
|
||||
},
|
||||
"homepage": "https://github.com/silverstripe/silverstripe-dms#readme"
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
@import "compass/css3";
|
||||
|
||||
@import '_mixins';
|
||||
|
||||
$color-button-generic: #e6e6e6 !default;
|
||||
|
||||
form.small .field input.text,
|
||||
form.small .field textarea,
|
||||
form.small .field select,
|
||||
form.small .field .TreeDropdownField,
|
||||
.field.small input.text, .field.small textarea,
|
||||
.field.small select, .field.small .TreeDropdownField{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#FileP{
|
||||
.fieldgroup-field{
|
||||
width:100%;
|
||||
.cms-file-info-preview{
|
||||
box-shadow:none;
|
||||
}
|
||||
.cms-file-info-data{
|
||||
width:400px;
|
||||
}
|
||||
.fieldholder-small{
|
||||
margin-top: 5px;
|
||||
label{
|
||||
width:auto;
|
||||
margin-left: 0;
|
||||
padding-top: 0;
|
||||
margin-right: 10px;
|
||||
font-weight: bold;
|
||||
float: left;
|
||||
}
|
||||
.readonly{
|
||||
font-style:italic;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#DocumentTypeID{
|
||||
@include tabButtons;
|
||||
}
|
||||
|
||||
#Actions{
|
||||
box-shadow:none;
|
||||
border:none;
|
||||
padding:0;
|
||||
li{
|
||||
margin-left: 2px;
|
||||
&:first-child{
|
||||
margin-left: 0;
|
||||
}
|
||||
&.delete-button-appended{
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin-left: 0;
|
||||
}
|
||||
&.dms-active{
|
||||
@include active-actions-btn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.DMSDocumentActionsPanel{
|
||||
|
||||
/*.middleColumn{
|
||||
margin-left:184px;
|
||||
width: 510px;
|
||||
form.small &{
|
||||
margin-left: 120px;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*label.fieldholder-small-label{
|
||||
display: none;
|
||||
}*/
|
||||
|
||||
|
||||
.fieldgroup {
|
||||
display: none;
|
||||
float:none;
|
||||
width:auto;
|
||||
background: #f8f8f8;
|
||||
padding: 15px;
|
||||
border: 1px solid #d0d3d5;
|
||||
@include border-radius(5px);
|
||||
|
||||
.fieldholder-small{
|
||||
label{
|
||||
float:none;
|
||||
width:auto;
|
||||
margin:0;
|
||||
padding:0;
|
||||
&.ss-ui-button{
|
||||
float: left;
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.embargo, .expiry{
|
||||
li{
|
||||
float: none;
|
||||
width: 100%;
|
||||
margin-left: 8px;
|
||||
label{
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
.embargoDatetime, .expiryDatetime{
|
||||
margin-top: 0;
|
||||
margin-left: 34px;
|
||||
overflow: hidden;
|
||||
.field{
|
||||
&.date, &.time{
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
&.date{
|
||||
.middleColumn{
|
||||
background: url('../images/calendar-month.png') 90px 7px no-repeat;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
&.time{
|
||||
.middleColumn{
|
||||
background: url('../images/clock-frame.png') 90px 7px no-repeat;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
.middleColumn{
|
||||
margin-left: 0;
|
||||
width: auto;
|
||||
border: none;
|
||||
input{
|
||||
width: 80px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Embargo {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
}
|
||||
|
||||
.ss-uploadfield-files{
|
||||
.ss-uploadfield-item-preview{
|
||||
background: url('../images/app_icons/generic_32.png') -10px -6px no-repeat;
|
||||
}
|
||||
.ss-uploadfield-item-name{
|
||||
span.name{
|
||||
width: 260px;
|
||||
}
|
||||
}
|
||||
.ss-uploadfield-item-actions{
|
||||
.ss-uploadfield-item-cancel{
|
||||
width: auto;
|
||||
text-indent:0;
|
||||
.btn-icon-deleteLight{
|
||||
background-position: 0 -128px;
|
||||
display: inline-block;
|
||||
}
|
||||
.ui-button-text{
|
||||
display: block;
|
||||
position: relative;
|
||||
float: right;
|
||||
color: #555;
|
||||
padding:0;
|
||||
padding-left: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > .fieldgroup.middleColumn {
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
.fieldgroup-field {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Form_ItemEditForm{
|
||||
fieldset{
|
||||
table.ss-gridfield-table{
|
||||
width: 494px;
|
||||
//max-width:508px;
|
||||
tr{
|
||||
th.main{
|
||||
min-width:175px;
|
||||
&.col-action_SetOrderID{
|
||||
width:60px;
|
||||
min-width:60px;
|
||||
}
|
||||
}
|
||||
td{
|
||||
white-space:normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ui-datepicker-div{
|
||||
border: 1px solid #DDD;
|
||||
}
|
|
@ -1,349 +0,0 @@
|
|||
@import '_mixins';
|
||||
|
||||
//data-icon="cross-circle"
|
||||
$gf_colour_zebra: #F0F4F7;
|
||||
|
||||
.ui-autocomplete{
|
||||
border: 1px solid #DDD;
|
||||
box-shadow: 0 1px 2px 0px #AFAFAF;
|
||||
max-height: 300px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.cms fieldset.documents, .cms fieldset.relatedLinks{
|
||||
table{
|
||||
td{
|
||||
white-space:normal;
|
||||
}
|
||||
td.col-buttons{
|
||||
white-space:nowrap;
|
||||
.dms-delete-link-only{
|
||||
.ui-icon{
|
||||
background: url(../images/chain-unchain.png) no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
tr.dms-document-hidden-row {
|
||||
&.odd {
|
||||
background-color: mix($gf_colour_zebra, rgba(255, 4, 0, 0.2));
|
||||
}
|
||||
&.even {
|
||||
background-color: mix($gf_colour_zebra, rgba(255, 4, 0, 0.35));
|
||||
}
|
||||
&:hover {
|
||||
background-color: mix($gf_colour_zebra, rgba(255, 4, 0, 0.6)) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.DMSDocumentAddController .ui-tabs{
|
||||
ul.ui-tabs-nav{
|
||||
border-bottom:none;
|
||||
float: right;
|
||||
margin: 8px 0 -1px 0;
|
||||
padding: 0 24px 0 0;
|
||||
li{
|
||||
padding-bottom: 1px;
|
||||
border: 1px solid #C0C0C2;
|
||||
a{
|
||||
padding: 8px 20px 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ss-add {
|
||||
.document-add-existing {
|
||||
input.document-autocomplete {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
//top: 70px;
|
||||
width: 390px;
|
||||
padding: 9px 7px;
|
||||
border-bottom-right-radius:0;
|
||||
border-top-right-radius:0;
|
||||
outline:none;
|
||||
box-sizing:border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
|
||||
&[disabled] {
|
||||
color: #C0C0C2;
|
||||
text-shadow: 0 -1px 0 #FFF;
|
||||
background: #EEE;
|
||||
background-image:none;
|
||||
box-shadow: inset 0 1px 8px 0 #C4C4C4;
|
||||
border-bottom-left-radius:0;
|
||||
border-bottom-right-radius:0;
|
||||
}
|
||||
}
|
||||
.TreeDropdownField {
|
||||
border:none;
|
||||
width: 100%;
|
||||
max-width: 512px;
|
||||
box-sizing: border-box;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.treedropdownfield-toggle-panel-link {
|
||||
padding: 5px 9px 9px;
|
||||
background: #fff;
|
||||
border: 1px solid #B3B3B3;
|
||||
float: right;
|
||||
z-index: 99999;
|
||||
position: relative;
|
||||
|
||||
&.treedropdownfield-open-tree {
|
||||
background: #fff;
|
||||
border: 1px solid #B3B3B3;
|
||||
border-bottom:none;
|
||||
border-bottom-right-radius:0;
|
||||
}
|
||||
}
|
||||
.treedropdownfield-title {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.treedropdownfield-toggle-panel-link a {
|
||||
display: inline-block;
|
||||
top: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.document-list {
|
||||
width: 510px;
|
||||
border: 1px solid #DDD;
|
||||
border-top:none;
|
||||
background: #ffffff;
|
||||
display: none;
|
||||
box-shadow:0 2px 4px 1px #DDD;
|
||||
max-height:300px;
|
||||
border-radius: 6px;
|
||||
background-clip: padding-box;
|
||||
overflow:scroll;
|
||||
|
||||
p {
|
||||
padding: 10px 10px 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 4px 0;
|
||||
|
||||
li {
|
||||
line-height:18px;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid #FFF;
|
||||
color: black;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid #CCC;
|
||||
border-radius: 4px;
|
||||
background: rgba(203, 203, 203, 0.4);
|
||||
cursor: pointer;
|
||||
text-decoration:none;
|
||||
outline:none;
|
||||
text-shadow:none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.link-editor-context{
|
||||
label{
|
||||
float: left;
|
||||
display: block;
|
||||
width: 176px;
|
||||
padding:8px 8px 8px 0;
|
||||
line-height: 16px;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px 0 white;
|
||||
}
|
||||
.middleColumn{
|
||||
margin-left: 184px;
|
||||
input{
|
||||
background:white;
|
||||
border: 1px solid #B3B3B3;
|
||||
line-height: 16px;
|
||||
margin: 0;
|
||||
border-radius: 4px;
|
||||
background-size: 100%;
|
||||
max-width: 512px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ss-assetuploadfield{
|
||||
&.link-editor-context{
|
||||
label{
|
||||
float: left;
|
||||
display: block;
|
||||
width: 176px;
|
||||
padding:8px 8px 8px 0;
|
||||
line-height: 16px;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px 0 white;
|
||||
}
|
||||
.middleColumn{
|
||||
margin-left: 184px;
|
||||
display: block;
|
||||
padding: 8px 8px 8px 0;
|
||||
font-style: italic;
|
||||
min-height:20px;
|
||||
}
|
||||
}
|
||||
.step4{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Styling for tree dropdown field
|
||||
.cms{
|
||||
.ss-add, .selectiongroup{
|
||||
.treedropdownfield-panel {
|
||||
margin: -1px 0 0 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
ul {
|
||||
padding: 4px 0;
|
||||
li {
|
||||
border: 1px solid #ffffff;
|
||||
a {
|
||||
display: block;
|
||||
padding: 4px 2px;
|
||||
|
||||
&.jstree-hovered {
|
||||
background: rgba(203, 203, 203, 0.4);
|
||||
border: 1px solid #CCC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Hack for Firefox to fix padding on adding document input.
|
||||
// FF renders the size different and pushes it out by 2px compared to webkit
|
||||
@-moz-document url-prefix() {
|
||||
.ss-add{
|
||||
.document-add-existing{
|
||||
input{
|
||||
padding: 10px 7px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Form_EditForm_Documents{
|
||||
padding: 1em 0;
|
||||
input[name="filter[LastChanged]"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#Form_EditForm_RelatedLinks{
|
||||
table{
|
||||
padding: 1em 0;
|
||||
thead{
|
||||
h2{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#SectionID, #DocumentTypeID{
|
||||
@include tabButtons;
|
||||
}
|
||||
|
||||
#Form_ItemEditForm{
|
||||
h3:first-child{
|
||||
display: inline-block;
|
||||
float: left;
|
||||
width: 184px;
|
||||
}
|
||||
ul.SelectionGroup{
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin-top: 9px;
|
||||
margin-left: 0;
|
||||
height: 110px;
|
||||
background: none;
|
||||
border: none;
|
||||
li{
|
||||
width: auto;
|
||||
clear: none;
|
||||
display: inline;
|
||||
margin-right: 4px;
|
||||
input{
|
||||
&.selector{
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
label{
|
||||
&.ui-button{
|
||||
@include background(
|
||||
linear-gradient(color-stops(
|
||||
lighten($color-button-generic, 10%),
|
||||
darken($color-button-generic, 5%)
|
||||
))
|
||||
);
|
||||
font-weight: bold;
|
||||
border: 1px solid #C0C0C2;
|
||||
border-radius: 3px;
|
||||
padding: 0.8em 1.5em;
|
||||
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
div.field{
|
||||
margin-left: 0px;
|
||||
margin-bottom: 1em;
|
||||
width: 600px;
|
||||
position: absolute;
|
||||
left:0;
|
||||
margin-top: 13px;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
border: 1px solid #B3B3B3;
|
||||
@include border-radius(4px);
|
||||
@include background-image(linear-gradient(#efefef, #fff 10%, #fff 90%, #efefef));
|
||||
}
|
||||
&.selected{
|
||||
label.ui-button{
|
||||
@include active-actions-btn;
|
||||
|
||||
&:after {
|
||||
top: 43px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.treedropdownfield-panel{
|
||||
margin: 1px 0 0 -1px;
|
||||
box-sizing: content-box;
|
||||
ul{
|
||||
li{
|
||||
display: block;
|
||||
clear: both;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,85 +1,7 @@
|
|||
@import "compass/css3";
|
||||
$color-button-generic: #e6e6e6 !default;
|
||||
|
||||
|
||||
@mixin tabButtons{
|
||||
.middleColumn{
|
||||
overflow:auto;
|
||||
min-width: 800px;
|
||||
ul{
|
||||
padding:0;
|
||||
input[type="radio"]{
|
||||
display:none;
|
||||
}
|
||||
li{
|
||||
display:table;
|
||||
padding: 0;
|
||||
width:125px;
|
||||
height:40px;
|
||||
white-space:normal;
|
||||
margin-right: -1px;
|
||||
border-radius: 0;
|
||||
&:first-child{
|
||||
border-radius: 6px 0 0 6px;
|
||||
border-left: 1px solid #C0C0C2;
|
||||
}
|
||||
&:last-child{
|
||||
border-radius: 0 6px 6px 0;
|
||||
}
|
||||
&.selected, .ie8 &.selected{
|
||||
border-bottom:1px solid #C0C0C2;
|
||||
@include background(
|
||||
linear-gradient(color-stops(
|
||||
darken($color-button-generic, 15%),
|
||||
$color-button-generic
|
||||
))
|
||||
);
|
||||
background-color: darken($color-button-generic, 15%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6'); /* IE6 & IE7 */
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6')"; /* IE8 */
|
||||
box-shadow: 0 1px 1px 0 #A0A0A0 inset;
|
||||
:after{
|
||||
box-shadow: 0 1px 1px 0 #DDD;
|
||||
}
|
||||
}
|
||||
label{
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//** Generate a state for an active list item link
|
||||
//
|
||||
// @param {string} $color - the colour to use for the border
|
||||
// @param {string} $size - the size the border should be, e.g. "8px"
|
||||
@mixin dmsdocument-actions-active($color, $size: "4px") {
|
||||
border-bottom: #{$size} solid #{$color};
|
||||
}
|
||||
|
||||
@mixin active-actions-btn{
|
||||
border-bottom:1px solid #C0C0C2;
|
||||
@include background(
|
||||
linear-gradient(color-stops(
|
||||
darken($color-button-generic, 15%),
|
||||
$color-button-generic
|
||||
))
|
||||
);
|
||||
background-color: darken($color-button-generic, 15%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6'); /* IE6 & IE7 */
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#C0C0C2', endColorstr='#E6E6E6')"; /* IE8 */
|
||||
box-shadow: 0 1px 1px 0 #A0A0A0 inset;
|
||||
&:after{
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 33px;
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: #F8F8F8;
|
||||
border-right: 1px solid #B3B3B3;
|
||||
border-top: 1px solid #B3B3B3;
|
||||
-moz-transform:rotate(-45deg);
|
||||
-webkit-transform:rotate(-45deg);
|
||||
pointer-events:none;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
//** Default values for colours, sizes etc
|
||||
|
||||
// Colours
|
||||
$color-button-generic: #e6e6e6 !default;
|
||||
$color-zebra: #F0F4F7 !default;
|
||||
|
||||
$color-grey-lighter: #f8f8f8 !default;
|
||||
$color-grey-light: #d0d3d5 !default;
|
||||
$color-grey-dark: #66727d !default;
|
||||
$color-white: #ffffff !default;
|
||||
|
||||
$color-cms-input-border: #b3b3b3 !default;
|
|
@ -0,0 +1,203 @@
|
|||
//** The DMS document details/information on an edit page
|
||||
.dmsdocument-documentdetails {
|
||||
.fieldgroup-field {
|
||||
.cms-file-info-preview {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.cms-file-info-data {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.fieldholder-small {
|
||||
margin-top: 5px;
|
||||
|
||||
.fieldholder-small-label {
|
||||
font-weight: bold;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.readonly {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//** The actions panel buttons when editing a DMS document
|
||||
.dmsdocment-actions {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
|
||||
label.left {
|
||||
padding: 6px 0 0 0;
|
||||
}
|
||||
|
||||
.ss-ui-button {
|
||||
border: none;
|
||||
background: none;
|
||||
border-radius: 0;
|
||||
font-weight: normal;
|
||||
|
||||
.ui-button-text {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
&.dms-active,
|
||||
&.dms-active:hover {
|
||||
@include dmsdocument-actions-active($color-grey-dark);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
background: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//** The actions panel, containing mini forms for each DMS document action
|
||||
.dmsdocument-actionspanel {
|
||||
margin-top: 0;
|
||||
|
||||
.fieldgroup {
|
||||
border: 1px solid $color-grey-light;
|
||||
display: none;
|
||||
margin-left: 0;
|
||||
padding: 5px 15px;
|
||||
|
||||
.fieldholder-small {
|
||||
label {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.embargo,
|
||||
.expiry {
|
||||
li {
|
||||
margin-left: 8px;
|
||||
width: 100%;
|
||||
|
||||
label {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.embargoDatetime,
|
||||
.expiryDatetime {
|
||||
float: left;
|
||||
margin-top: 0;
|
||||
margin-left: 34px;
|
||||
overflow: hidden;
|
||||
|
||||
.field {
|
||||
&.date,
|
||||
&.time {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
|
||||
.middleColumn {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&.date {
|
||||
.middleColumn {
|
||||
background: url('../images/calendar-month.png') 90px 7px no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
&.time {
|
||||
.middleColumn {
|
||||
background: url('../images/clock-frame.png') 90px 7px no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.middleColumn {
|
||||
border: none;
|
||||
margin-left: 0;
|
||||
width: auto;
|
||||
|
||||
input.date,
|
||||
input.time {
|
||||
margin-right: 40px;
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fieldgroup-field label {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ss-uploadfield-files {
|
||||
.ss-uploadfield-item-preview {
|
||||
background: url('../images/app_icons/generic_32.png') -10px -6px no-repeat;
|
||||
}
|
||||
|
||||
.ss-uploadfield-item-name {
|
||||
span.name {
|
||||
width: 260px;
|
||||
}
|
||||
}
|
||||
|
||||
.ss-uploadfield-item-actions {
|
||||
.ss-uploadfield-item-cancel {
|
||||
text-indent: 0;
|
||||
width: auto;
|
||||
|
||||
.btn-icon-deleteLight {
|
||||
background-position: 0 -128px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ui-button-text {
|
||||
color: $color-grey-dark;
|
||||
display: block;
|
||||
float: right;
|
||||
padding: 0 0 0 2em;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > .fieldgroup.middleColumn {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
|
||||
.fieldgroup-field {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.permissions {
|
||||
.fieldholder-small {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ui-datepicker-div {
|
||||
border: 1px solid $color-grey-light;
|
||||
}
|
||||
|
||||
//** Overrides for the inline edit screen
|
||||
form.small .field input.text,
|
||||
form.small .field textarea,
|
||||
form.small .field select,
|
||||
form.small .field .TreeDropdownField,
|
||||
.field.small input.text,
|
||||
.field.small textarea,
|
||||
.field.small select,
|
||||
.field.small .TreeDropdownField {
|
||||
width: 100%;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
@import "_variables";
|
||||
@import "_mixins";
|
||||
@import "cmsfields";
|
||||
@import "upload";
|
|
@ -0,0 +1,273 @@
|
|||
.dmsdocument-addexisting {
|
||||
.ui-autocomplete {
|
||||
border: 1px solid $color-grey-light;
|
||||
max-height: 300px;
|
||||
overflow: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
.ss-add {
|
||||
.document-add-existing {
|
||||
input.document-autocomplete {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
width: 390px;
|
||||
padding: 9px 7px;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
|
||||
&[disabled] {
|
||||
color: $color-grey-light;
|
||||
text-shadow: 0 -1px 0 $color-white;
|
||||
background: $color-grey-lighter;
|
||||
background-image:none;
|
||||
box-shadow: inset 0 1px 8px 0 $color-grey-light;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.treedropdown {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.treedropdownfield-toggle-panel-link {
|
||||
padding: 5px 9px 9px;
|
||||
background: #fff;
|
||||
border: 1px solid $color-cms-input-border;
|
||||
float: right;
|
||||
z-index: 99999;
|
||||
position: relative;
|
||||
|
||||
&.treedropdownfield-open-tree {
|
||||
background: #fff;
|
||||
border: 1px solid $color-cms-input-border;
|
||||
border-bottom:none;
|
||||
border-bottom-right-radius:0;
|
||||
}
|
||||
}
|
||||
|
||||
.treedropdownfield-title {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.treedropdownfield-toggle-panel-link a {
|
||||
display: inline-block;
|
||||
top: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.document-list {
|
||||
width: 510px;
|
||||
border: 1px solid $color-grey-light;
|
||||
border-top: none;
|
||||
background: $color-white;
|
||||
display: none;
|
||||
max-height: 300px;
|
||||
background-clip: padding-box;
|
||||
overflow: scroll;
|
||||
|
||||
p {
|
||||
padding: 10px 10px 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 4px 0;
|
||||
|
||||
li {
|
||||
line-height: 18px;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid $color-white;
|
||||
color: black;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid $color-grey-light;
|
||||
border-radius: 4px;
|
||||
background: rgba(203, 203, 203, 0.4);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When inserting a link to a document via the TinyMCE editor
|
||||
&.link-editor-context {
|
||||
label {
|
||||
float: left;
|
||||
display: block;
|
||||
width: 176px;
|
||||
padding: 8px 8px 8px 0;
|
||||
line-height: 16px;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px 0 white;
|
||||
}
|
||||
|
||||
.middleColumn {
|
||||
input {
|
||||
background: white;
|
||||
border: 1px solid $color-cms-input-border;
|
||||
line-height: 16px;
|
||||
border-radius: 4px;
|
||||
background-size: 100%;
|
||||
max-width: 468px;
|
||||
|
||||
&.document-autocomplete {
|
||||
max-width: 365px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.document-list {
|
||||
width: calc(100% - 2px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ss-assetuploadfield {
|
||||
&.link-editor-context {
|
||||
label {
|
||||
float: left;
|
||||
display: block;
|
||||
width: 176px;
|
||||
padding: 8px 8px 8px 0;
|
||||
line-height: 16px;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px 0 white;
|
||||
}
|
||||
|
||||
.middleColumn {
|
||||
margin-left: 184px;
|
||||
display: block;
|
||||
padding: 8px 8px 8px 0;
|
||||
font-style: italic;
|
||||
min-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.step4 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Styling for tree dropdown field
|
||||
.cms {
|
||||
.ss-add,
|
||||
.selectiongroup {
|
||||
.treedropdownfield-panel {
|
||||
margin: -1px 0 0 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
ul {
|
||||
padding: 4px 0;
|
||||
|
||||
li {
|
||||
border: 1px solid $color-white;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: 4px 2px;
|
||||
|
||||
&.jstree-hovered {
|
||||
background: rgba(203, 203, 203, 0.4);
|
||||
border: 1px solid $color-grey-light;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Form_ItemEditForm {
|
||||
h3:first-child {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
width: 184px;
|
||||
}
|
||||
|
||||
ul.SelectionGroup {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin-top: 9px;
|
||||
margin-left: 0;
|
||||
height: 110px;
|
||||
background: none;
|
||||
border: none;
|
||||
|
||||
li {
|
||||
width: auto;
|
||||
clear: none;
|
||||
display: inline;
|
||||
margin-right: 4px;
|
||||
|
||||
input {
|
||||
&.selector {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
&.ui-button {
|
||||
font-weight: bold;
|
||||
border: 1px solid #C0C0C2;
|
||||
border-radius: 3px;
|
||||
padding: 0.8em 1.5em;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.field {
|
||||
margin-left: 0px;
|
||||
margin-bottom: 1em;
|
||||
width: 600px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
margin-top: 13px;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
border: 1px solid $color-cms-input-border;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
label.ui-button {
|
||||
&:after {
|
||||
top: 43px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.treedropdownfield-panel {
|
||||
margin: 1px 0 0 -1px;
|
||||
box-sizing: content-box;
|
||||
|
||||
ul {
|
||||
li {
|
||||
display: block;
|
||||
clear: both;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +1,43 @@
|
|||
<div id="document" class="ss-add field treedropdown searchable">
|
||||
<div class="document-add-existing <% if useFieldContext %>field<% else %>link-editor-context<% end_if %>">
|
||||
<% if useFieldContext %>
|
||||
<h3>
|
||||
<% else %>
|
||||
<div>
|
||||
<% end_if %>
|
||||
<span class="step-label">
|
||||
<% if useFieldContext %>
|
||||
<span class="flyout">1</span><span class="arrow"></span>
|
||||
<strong class="title">Link a Document</strong>
|
||||
<% else %>
|
||||
<% end_if %>
|
||||
</span>
|
||||
<% if useFieldContext %>
|
||||
</h3>
|
||||
<% else %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
<div class="ss-add field treedropdown searchable dmsdocument-addexisting">
|
||||
<div class="document-add-existing <% if $useFieldContext %>field<% else %>link-editor-context<% end_if %>">
|
||||
<% if $useFieldContext %><h3><% else %><div><% end_if %>
|
||||
<span class="step-label">
|
||||
<% if $useFieldContext %>
|
||||
<span class="flyout">1</span><span class="arrow"></span>
|
||||
<strong class="title"><%t DMSDocumentAddExistingField.LINKADOCUMENT "Link a Document" %></strong>
|
||||
<% end_if %>
|
||||
</span>
|
||||
<% if $useFieldContext %></h3><% else %></div><% end_if %>
|
||||
|
||||
<% if useFieldContext %>
|
||||
<% else %>
|
||||
<label>Link a Document</label>
|
||||
<div class="middleColumn">
|
||||
<% end_if %>
|
||||
|
||||
<input class="document-autocomplete text" type="text" placeholder="Search by ID or filename" />
|
||||
<!-- <span>or Add from page</span> -->
|
||||
$fieldByName(PageSelector)
|
||||
<% if not $useFieldContext %>
|
||||
<label><%t DMSDocumentAddExistingField.LINKADOCUMENT "Link a Document" %></label>
|
||||
<div class="middleColumn">
|
||||
<% end_if %>
|
||||
<input class="document-autocomplete text" type="text" placeholder="<%t DMSDocumentAddExistingField.AUTOCOMPLETE "Search by ID or filename" %>" />
|
||||
$fieldByName(PageSelector)
|
||||
<div class="document-list"></div>
|
||||
<% if not $useFieldContext %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
</div>
|
||||
|
||||
<div class="document-list"></div>
|
||||
|
||||
<% if useFieldContext %>
|
||||
<% else %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="ss-assetuploadfield <% if useFieldContext %>field<% else %>link-editor-context<% end_if %>">
|
||||
<div class="step4">
|
||||
<span class="step-label">
|
||||
<% if useFieldContext %>
|
||||
<span class="flyout">2</span><span class="arrow"></span>
|
||||
<strong class="title">Edit Document Details</strong>
|
||||
<% else %>
|
||||
<label>Selected Document</label>
|
||||
<% end_if %>
|
||||
</span>
|
||||
</div>
|
||||
<!-- <div class="fileOverview"></div> -->
|
||||
|
||||
<% if useFieldContext %>
|
||||
<% else %>
|
||||
<div class="middleColumn">
|
||||
<% end_if %>
|
||||
<ul class="files ss-uploadfield-files ss-add-files"></ul>
|
||||
<% if useFieldContext %>
|
||||
<% else %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="ss-assetuploadfield <% if useFieldContext %>field<% else %>link-editor-context<% end_if %>">
|
||||
<div class="step4">
|
||||
<span class="step-label">
|
||||
<% if useFieldContext %>
|
||||
<span class="flyout">2</span><span class="arrow"></span>
|
||||
<strong class="title"><%t DMSDocumentAddExistingField.EDITDOCUMENTDETAILS "Edit Document Details" %></strong>
|
||||
<% else %>
|
||||
<label><%t DMSDocumentAddExistingField.SELECTED "Selected Document" %></label>
|
||||
<% end_if %>
|
||||
</span>
|
||||
</div>
|
||||
<% if not $useFieldContext %>
|
||||
<div class="middleColumn">
|
||||
<% end_if %>
|
||||
<ul class="files ss-uploadfield-files ss-add-files"></ul>
|
||||
<% if not $useFieldContext %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<div class="clear"><!-- --></div>
|
||||
</label>
|
||||
<div class="ss-uploadfield-item-actions">
|
||||
<% if Top.isDisabled || Top.isReadonly %>
|
||||
<% if $Top.isDisabled || $Top.isReadonly %>
|
||||
<% else %>
|
||||
$UploadFieldFileButtons
|
||||
<% end_if %>
|
||||
|
@ -25,11 +25,11 @@
|
|||
<% end_loop %>
|
||||
<% end_if %>
|
||||
</ul>
|
||||
<% if isDisabled || isReadonly %>
|
||||
<% if isSaveable %>
|
||||
<% if $isDisabled || $isReadonly %>
|
||||
<% if $isSaveable %>
|
||||
<% else %>
|
||||
<div class="ss-uploadfield-item">
|
||||
<em><% _t('FileIFrameField.ATTACHONCESAVED2', 'Files can be attached once you have saved the record for the first time.') %></em>
|
||||
<em><%t FileIFrameField.ATTACHONCESAVED2 "Files can be attached once you have saved the record for the first time." %></em>
|
||||
</div>
|
||||
<% end_if %>
|
||||
<% else %>
|
||||
|
@ -41,8 +41,8 @@
|
|||
<label class="ss-uploadfield-item-name"><b>
|
||||
<% _t('UploadField.ATTACHFILE', 'Attach a file') %>
|
||||
</b></label>
|
||||
<label class="ss-uploadfield-fromcomputer ss-ui-button ui-corner-all" title="<% _t('UploadField.FROMCOMPUTERINFO', 'Upload from your computer') %>" data-icon="drive-upload">
|
||||
<% _t('UploadField.FROMCOMPUTER', 'From your computer') %>
|
||||
<label class="ss-uploadfield-fromcomputer ss-ui-button ui-corner-all" title="<%t UploadField.FROMCOMPUTERINFO 'Upload from your computer' %>" data-icon="drive-upload">
|
||||
<%t UploadField.FROMCOMPUTER 'From your computer' %>
|
||||
<input id="$id" name="$getName" class="$extraClass ss-uploadfield-fromcomputer-fileinput" data-config="$configString" type="file"<% if $multiple %> multiple="multiple"<% end_if %> />
|
||||
</label>
|
||||
<div class="clear"><!-- --></div>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<%-- Customised to change the button's link to the DMSDocumentAddController instead of the default --%>
|
||||
<a href="$NewLink" class="action action-detail ss-ui-action-constructive ss-ui-button ui-button ui-widget ui-state-default ui-corner-all new new-link" data-icon="add">
|
||||
$ButtonName
|
||||
</a>
|
|
@ -1,19 +1,20 @@
|
|||
<% if isHidden != true %>
|
||||
<div class="document $Extension">
|
||||
<% if Title %>
|
||||
<h4><a href="$Link" title="Download $Title">$Title</a></h4>
|
||||
<% else %>
|
||||
<h4><a href="$Link" title="Download $FilenameWithoutID">$FilenameWithoutID</a></h4>
|
||||
<% end_if %>
|
||||
|
||||
<p class='details'>
|
||||
<strong>$FilenameWithoutID</strong>
|
||||
| $Extension
|
||||
| $FileSizeFormatted
|
||||
| Last Changed: $LastChanged.Nice
|
||||
</p>
|
||||
<% if Description %>
|
||||
<p>$DescriptionWithLineBreak</p>
|
||||
<% end_if %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
<% if not $isHidden %>
|
||||
<div class="document $Extension">
|
||||
<h4><a href="$Link" title="<%t DMSDocument.DOWNLOAD "Download {title}" title=$getTitle %>">$getTitle</a></h4>
|
||||
|
||||
<% if $CoverImage %>
|
||||
<div class="article-thumbnail">
|
||||
$CoverImage.FitMax(100, 100)
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
<p class="details"><% include DocumentDetails %></p>
|
||||
<% if $Description %>
|
||||
<p>$DescriptionWithLineBreak</p>
|
||||
<% end_if %>
|
||||
|
||||
<% if $getRelatedDocuments %>
|
||||
<% include RelatedDocuments %>
|
||||
<% end_if %>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<strong>$FilenameWithoutID</strong>
|
||||
| $Extension
|
||||
| $FileSizeFormatted
|
||||
| <%t DMSDocument.LASTCHANGED "Last changed: {date}" date=$LastEdited.Nice %>
|
|
@ -0,0 +1,11 @@
|
|||
<% if $getDocuments %>
|
||||
<div class="documentsets-set">
|
||||
<% if $Title %>
|
||||
<h3>$Title</h3>
|
||||
<% end_if %>
|
||||
|
||||
<% loop $getDocuments.Sort(DocumentSort) %>
|
||||
<% include Document %>
|
||||
<% end_loop %>
|
||||
</div>
|
||||
<% end_if %>
|
|
@ -0,0 +1,7 @@
|
|||
<% if $getDocumentSets %>
|
||||
<div class="documentsets">
|
||||
<% loop $getDocumentSets %>
|
||||
<% include DocumentSet %>
|
||||
<% end_loop %>
|
||||
</div>
|
||||
<% end_if %>
|
|
@ -1,4 +0,0 @@
|
|||
<% if PageDocuments %>
|
||||
<div><h3>Documents:</h3></div>
|
||||
<% loop PageDocuments %><% include Document %><% end_loop %>
|
||||
<% end_if %>
|
|
@ -0,0 +1,14 @@
|
|||
<h5><%t DMSDocument.RELATED_DOCUMENTS "Related documents" %></h5>
|
||||
|
||||
<ul class="documents-relateddocuments">
|
||||
<% loop $getRelatedDocuments %>
|
||||
<li>
|
||||
<% if $Title %>
|
||||
<a href="$Link" title="<%t DMSDocument.DOWNLOAD "Download {title}" title=$Title %>">$Title</a>
|
||||
<% else %>
|
||||
<a href="$Link" title="<%t DMSDocument.DOWNLOAD "Download {title}" title=$FilenameWithoutID %>">$FilenameWithoutID</a>
|
||||
<% end_if %>
|
||||
<span class="documents-relateddocuments-documentdetails"><% include DocumentDetails %></span>
|
||||
</li>
|
||||
<% end_loop %>
|
||||
</ul>
|
|
@ -3,52 +3,69 @@
|
|||
/**
|
||||
* Class DMSDocumentControllerTest
|
||||
*/
|
||||
class DMSDocumentControllerTest extends SapphireTest {
|
||||
class DMSDocumentControllerTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'dmstest.yml';
|
||||
|
||||
protected static $fixture_file = "dmstest.yml";
|
||||
/**
|
||||
* @var DMSDocument_Controller
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
public function testDownloadBehaviourOpen() {
|
||||
DMS::$dmsFolder = DMS_DIR; //sneakily setting the DMS folder to the folder where the test file lives
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Config::inst()->update('DMS', 'folder_name', 'assets/_unit-test-123');
|
||||
$this->logInWithPermission('ADMIN');
|
||||
/** @var DMSDocument_Controller $controller */
|
||||
$controller = $this->getMockBuilder('DMSDocument_Controller')
|
||||
->setMethods(array('sendFile'))->getMock();
|
||||
$self = $this;
|
||||
$controller->expects($this->once())->method('sendFile')->will($this->returnCallback(function($path, $mime, $name, $disposition) use($self) {
|
||||
$self->assertEquals('inline', $disposition);
|
||||
}));
|
||||
$openDoc = new DMSDocument();
|
||||
$openDoc->Filename = "DMS-test-lorum-file.pdf";
|
||||
$openDoc->Folder = "tests";
|
||||
$openDoc->DownloadBehavior = 'open';
|
||||
$openDoc->clearEmbargo(false);
|
||||
$openDoc->write();
|
||||
$request = new SS_HTTPRequest('GET', 'index/' . $openDoc->ID);
|
||||
$request->match('index/$ID');
|
||||
$controller->index($request);
|
||||
|
||||
$this->controller = $this->getMockBuilder('DMSDocument_Controller')
|
||||
->setMethods(array('sendFile'))
|
||||
->getMock();
|
||||
}
|
||||
|
||||
public function testDownloadBehaviourDownload() {
|
||||
DMS::$dmsFolder = DMS_DIR; //sneakily setting the DMS folder to the folder where the test file lives
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
/** @var DMSDocument_Controller $controller */
|
||||
$controller = $this->getMockBuilder('DMSDocument_Controller')
|
||||
->setMethods(array('sendFile'))->getMock();
|
||||
$self = $this;
|
||||
$controller->expects($this->once())->method('sendFile')->will($this->returnCallback(function($path, $mime, $name, $disposition) use($self) {
|
||||
$self->assertEquals('attachment', $disposition);
|
||||
}));
|
||||
$openDoc = new DMSDocument();
|
||||
$openDoc->Filename = "DMS-test-lorum-file.pdf";
|
||||
$openDoc->Folder = "tests";
|
||||
$openDoc->DownloadBehavior = 'download';
|
||||
$openDoc->clearEmbargo(false);
|
||||
$openDoc->write();
|
||||
$request = new SS_HTTPRequest('GET', 'index/' . $openDoc->ID);
|
||||
$request->match('index/$ID');
|
||||
$controller->index($request);
|
||||
public function tearDown()
|
||||
{
|
||||
DMSFilesystemTestHelper::delete('assets/_unit-test-123');
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the download behaviour is either "open" or "download"
|
||||
*
|
||||
* @param string $behaviour
|
||||
* @param string $expectedDisposition
|
||||
* @dataProvider behaviourProvider
|
||||
*/
|
||||
public function testDownloadBehaviourOpen($behaviour, $expectedDisposition)
|
||||
{
|
||||
$self = $this;
|
||||
$this->controller->expects($this->once())
|
||||
->method('sendFile')
|
||||
->will(
|
||||
$this->returnCallback(function ($path, $mime, $name, $disposition) use ($self, $expectedDisposition) {
|
||||
$self->assertEquals($expectedDisposition, $disposition);
|
||||
})
|
||||
);
|
||||
|
||||
$openDoc = DMS::inst()->storeDocument('dms/tests/DMS-test-lorum-file.pdf');
|
||||
$openDoc->DownloadBehavior = $behaviour;
|
||||
$openDoc->clearEmbargo(false);
|
||||
$openDoc->write();
|
||||
|
||||
$request = new SS_HTTPRequest('GET', $openDoc->Link());
|
||||
$request->match('dmsdocument/$ID');
|
||||
$this->controller->index($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
public function behaviourProvider()
|
||||
{
|
||||
return array(
|
||||
array('open', 'inline'),
|
||||
array('download', 'attachment')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,270 @@
|
|||
<?php
|
||||
|
||||
class DMSDocumentSetTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'dmstest.yml';
|
||||
|
||||
/**
|
||||
* Ensure that getDocuments is extensible
|
||||
*/
|
||||
public function testGetDocumentsIsExtensible()
|
||||
{
|
||||
DMSDocumentSet::add_extension('StubRelatedDocumentExtension');
|
||||
|
||||
$set = new DMSDocumentSet;
|
||||
$documents = $set->getDocuments();
|
||||
|
||||
$this->assertCount(1, $documents);
|
||||
$this->assertSame('Extended', $documents->first()->Filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the GridField for documents isn't shown until you've saved the set
|
||||
*/
|
||||
public function testGridFieldShowsWhenSetIsSaved()
|
||||
{
|
||||
$set = DMSDocumentSet::create();
|
||||
|
||||
// Not in database yet
|
||||
$fields = $set->getCMSFields();
|
||||
$this->assertNull($fields->fieldByName('Root.Main.Documents'));
|
||||
$gridFieldNotice = $fields->fieldByName('Root.Main.GridFieldNotice');
|
||||
$this->assertNotNull($gridFieldNotice);
|
||||
$this->assertContains('Managing documents will be available', $gridFieldNotice->getContent());
|
||||
|
||||
// In the database
|
||||
$set->Title = 'Testing';
|
||||
$set->write();
|
||||
$fields = $set->getCMSFields();
|
||||
$this->assertNotNull($fields->fieldByName('Root.Main.Documents'));
|
||||
$this->assertNull($fields->fieldByName('Root.Main.GridFieldNotice'));
|
||||
}
|
||||
|
||||
public function testRelations()
|
||||
{
|
||||
$s1 = $this->objFromFixture('SiteTree', 's1');
|
||||
$s2 = $this->objFromFixture('SiteTree', 's2');
|
||||
$s4 = $this->objFromFixture('SiteTree', 's4');
|
||||
|
||||
$ds1 = $this->objFromFixture('DMSDocumentSet', 'ds1');
|
||||
$ds2 = $this->objFromFixture('DMSDocumentSet', 'ds2');
|
||||
$ds3 = $this->objFromFixture('DMSDocumentSet', 'ds3');
|
||||
|
||||
$this->assertCount(0, $s4->getDocumentSets(), 'Page 4 has no document sets associated');
|
||||
$this->assertCount(2, $s1->getDocumentSets(), 'Page 1 has 2 document sets');
|
||||
$this->assertEquals(array($ds1->ID, $ds2->ID), $s1->getDocumentSets()->column('ID'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that various components exist in the GridField config. See {@link DMSDocumentSet::getCMSFields} for context.
|
||||
*/
|
||||
public function testDocumentGridFieldConfig()
|
||||
{
|
||||
$set = $this->objFromFixture('DMSDocumentSet', 'ds1');
|
||||
$fields = $set->getCMSFields();
|
||||
$gridField = $fields->fieldByName('Root.Main.Documents');
|
||||
$this->assertTrue((bool) $gridField->hasClass('documents'));
|
||||
|
||||
/** @var GridFieldConfig $config */
|
||||
$config = $gridField->getConfig();
|
||||
|
||||
$this->assertNotNull($addNew = $config->getComponentByType('DMSGridFieldAddNewButton'));
|
||||
$this->assertSame($set->ID, $addNew->getDocumentSetId());
|
||||
|
||||
if (class_exists('GridFieldPaginatorWithShowAll')) {
|
||||
$this->assertNotNull($config->getComponentByType('GridFieldPaginatorWithShowAll'));
|
||||
} else {
|
||||
$paginator = $config->getComponentByType('GridFieldPaginator');
|
||||
$this->assertNotNull($paginator);
|
||||
$this->assertSame(15, $paginator->getItemsPerPage());
|
||||
}
|
||||
|
||||
$sortableAssertion = class_exists('GridFieldSortableRows') ? 'assertNotNull' : 'assertNull';
|
||||
$this->$sortableAssertion($config->getComponentByType('GridFieldSortableRows'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the display fields for the documents GridField can be returned
|
||||
*/
|
||||
public function testGetDocumentDisplayFields()
|
||||
{
|
||||
$document = $this->objFromFixture('DMSDocumentSet', 'ds1');
|
||||
$this->assertInternalType('array', $document->getDocumentDisplayFields());
|
||||
|
||||
Config::inst()->update('DMSDocument', 'display_fields', array('apple' => 'Apple', 'orange' => 'Orange'));
|
||||
$displayFields = $document->getDocumentDisplayFields();
|
||||
$this->assertContains('Apple', $displayFields);
|
||||
$this->assertContains('Orange', $displayFields);
|
||||
$this->assertArrayHasKey('ManuallyAdded', $displayFields);
|
||||
$this->assertContains('Added', $displayFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to ensure that the callback for formatting ManuallyAdded will return a nice label for the user
|
||||
*/
|
||||
public function testNiceFormattingForManuallyAddedInGridField()
|
||||
{
|
||||
$fieldFormatting = $this->objFromFixture('DMSDocumentSet', 'ds1')
|
||||
->getCMSFields()
|
||||
->fieldByName('Root.Main.Documents')
|
||||
->getConfig()
|
||||
->getComponentByType('GridFieldDataColumns')
|
||||
->getFieldFormatting();
|
||||
|
||||
$this->assertArrayHasKey('ManuallyAdded', $fieldFormatting);
|
||||
$this->assertTrue(is_callable($fieldFormatting['ManuallyAdded']));
|
||||
|
||||
$this->assertSame('Manually', $fieldFormatting['ManuallyAdded'](1));
|
||||
$this->assertSame('Query Builder', $fieldFormatting['ManuallyAdded'](0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that query fields can be added to the gridfield
|
||||
*/
|
||||
public function testAddQueryFields()
|
||||
{
|
||||
/** @var DMSDocumentSet $set */
|
||||
$set = $this->objFromFixture('DMSDocumentSet', 'ds6');
|
||||
/** @var FieldList $fields */
|
||||
$fields = new FieldList(new TabSet('Root'));
|
||||
/** @var FieldList $fields */
|
||||
$set->addQueryFields($fields);
|
||||
$keyValuePairs = $fields->dataFieldByName('KeyValuePairs');
|
||||
$this->assertNotNull(
|
||||
$keyValuePairs,
|
||||
'addQueryFields() includes KeyValuePairs composite field'
|
||||
);
|
||||
$this->assertNotNull(
|
||||
$keyValuePairs->fieldByName('KeyValuePairs[Title]'),
|
||||
'addQueryFields() includes KeyValuePairs composite field'
|
||||
);
|
||||
|
||||
// Test that the notification field exists
|
||||
$this->assertNotNull($fields->fieldByName('Root.QueryBuilder.GridFieldNotice'));
|
||||
|
||||
// Test that Tags__ID field exists
|
||||
$this->assertContains(
|
||||
'Tags can be set in the taxonomy area,',
|
||||
$keyValuePairs->fieldByName('KeyValuePairs[Tags__ID]')->RightTitle()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the "direction" dropdown field has user friendly field labels
|
||||
*/
|
||||
public function testQueryBuilderDirectionFieldHasFriendlyLabels()
|
||||
{
|
||||
$fields = $this->objFromFixture('DMSDocumentSet', 'ds1')->getCMSFields();
|
||||
|
||||
$dropdown = $fields->fieldByName('Root.QueryBuilder')->FieldList()->filterByCallback(function ($field) {
|
||||
return $field instanceof FieldGroup;
|
||||
})->first()->fieldByName('SortByDirection');
|
||||
|
||||
$this->assertInstanceOf('DropdownField', $dropdown);
|
||||
$source = $dropdown->getSource();
|
||||
$this->assertContains('Ascending', $source);
|
||||
$this->assertContains('Descending', $source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the configurable shortcode handler key is a hidden field in the CMS
|
||||
*/
|
||||
public function testShortcodeHandlerKeyFieldExists()
|
||||
{
|
||||
Config::inst()->update('DMS', 'shortcode_handler_key', 'unit-test');
|
||||
|
||||
$set = DMSDocumentSet::create(array('Title' => 'TestSet'));
|
||||
$set->write();
|
||||
|
||||
$fields = $set->getCMSFields();
|
||||
$field = $fields->fieldByName('Root.Main.DMSShortcodeHandlerKey');
|
||||
|
||||
$this->assertInstanceOf('HiddenField', $field);
|
||||
$this->assertSame('unit-test', $field->Value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that if the module is available, the orderable rows GridField component is added
|
||||
*/
|
||||
public function testDocumentsAreOrderable()
|
||||
{
|
||||
if (!class_exists('GridFieldSortableRows')) {
|
||||
$this->markTestSkipped('Test requires undefinedoffset/sortablegridfield installed.');
|
||||
}
|
||||
|
||||
$fields = $this->objFromFixture('DMSDocumentSet', 'ds1')->getCMSFields();
|
||||
|
||||
$gridField = $fields->fieldByName('Root.Main.Documents');
|
||||
$this->assertInstanceOf('GridField', $gridField);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'GridFieldSortableRows',
|
||||
$gridField->getConfig()->getComponentByType('GridFieldSortableRows')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that extra documents are added after write
|
||||
*/
|
||||
public function testSaveLinkedDocuments()
|
||||
{
|
||||
/** @var DMSDocumentSet $set */
|
||||
$set = $this->objFromFixture('DMSDocumentSet', 'dsSaveLinkedDocuments');
|
||||
// Assert initially docs
|
||||
$this->assertEquals(1, $set->getDocuments()->count(), 'Set has 1 document');
|
||||
// Now apply the query and see if 2 extras were added with CreatedByID filter
|
||||
$set->KeyValuePairs = '{"Filename":"extradoc3"}';
|
||||
$set->saveLinkedDocuments();
|
||||
$this->assertEquals(2, $set->getDocuments()->count(), 'Set has 2 documents');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an exception is thrown if no title entered for a DMSDocumentSet.
|
||||
* @expectedException ValidationException
|
||||
*/
|
||||
public function testExceptionOnNoTitleGiven()
|
||||
{
|
||||
DMSDocumentSet::create(array('Title' => ''))->write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that when editing in a page context that the "page" field is removed, or is labelled "Show on page"
|
||||
* otherwise
|
||||
*/
|
||||
public function testPageFieldRemovedWhenEditingInPageContext()
|
||||
{
|
||||
$set = $this->objFromFixture('DMSDocumentSet', 'ds1');
|
||||
|
||||
$fields = $set->getCMSFields();
|
||||
$this->assertInstanceOf('DropdownField', $fields->fieldByName('Root.Main.PageID'));
|
||||
|
||||
$pageController = new CMSPageEditController;
|
||||
$pageController->pushCurrent();
|
||||
|
||||
$fields = $set->getCMSFields();
|
||||
$this->assertNull($fields->fieldByName('Root.Main.PageID'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests all crud permissions
|
||||
*/
|
||||
public function testPermissions()
|
||||
{
|
||||
if ($member = Member::currentUser()) {
|
||||
$member->logout();
|
||||
}
|
||||
|
||||
$set = $this->objFromFixture('DMSDocumentSet', 'ds1');
|
||||
|
||||
$this->assertFalse($set->canCreate());
|
||||
$this->assertFalse($set->canDelete());
|
||||
$this->assertFalse($set->canEdit());
|
||||
$this->assertFalse($set->canView());
|
||||
|
||||
$this->logInWithPermission('CMS_ACCESS_DMSDocumentAdmin');
|
||||
$this->assertTrue($set->canCreate());
|
||||
$this->assertTrue($set->canDelete());
|
||||
$this->assertTrue($set->canEdit());
|
||||
$this->assertTrue($set->canView());
|
||||
}
|
||||
}
|
|
@ -1,164 +1,10 @@
|
|||
<?php
|
||||
class DMSDocumentTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'dmstest.yml';
|
||||
|
||||
protected static $fixture_file = "dms/tests/dmstest.yml";
|
||||
|
||||
public function tearDownOnce()
|
||||
public function testDefaultDownloadBehabiourCMSFields()
|
||||
{
|
||||
self::$is_running_test = true;
|
||||
|
||||
$d = DataObject::get("DMSDocument");
|
||||
foreach ($d as $d1) {
|
||||
$d1->delete();
|
||||
}
|
||||
$t = DataObject::get("DMSTag");
|
||||
foreach ($t as $t1) {
|
||||
$t1->delete();
|
||||
}
|
||||
|
||||
self::$is_running_test = $this->originalIsRunningTest;
|
||||
}
|
||||
|
||||
public function testPageRelations()
|
||||
{
|
||||
$s1 = $this->objFromFixture('SiteTree', 's1');
|
||||
$s2 = $this->objFromFixture('SiteTree', 's2');
|
||||
$s3 = $this->objFromFixture('SiteTree', 's3');
|
||||
$s4 = $this->objFromFixture('SiteTree', 's4');
|
||||
$s5 = $this->objFromFixture('SiteTree', 's5');
|
||||
$s6 = $this->objFromFixture('SiteTree', 's6');
|
||||
|
||||
$d1 = $this->objFromFixture('DMSDocument', 'd1');
|
||||
|
||||
$pages = $d1->Pages();
|
||||
$pagesArray = $pages->toArray();
|
||||
$this->assertEquals($pagesArray[0]->ID, $s1->ID, "Page 1 associated correctly");
|
||||
$this->assertEquals($pagesArray[1]->ID, $s2->ID, "Page 2 associated correctly");
|
||||
$this->assertEquals($pagesArray[2]->ID, $s3->ID, "Page 3 associated correctly");
|
||||
$this->assertEquals($pagesArray[3]->ID, $s4->ID, "Page 4 associated correctly");
|
||||
$this->assertEquals($pagesArray[4]->ID, $s5->ID, "Page 5 associated correctly");
|
||||
$this->assertEquals($pagesArray[5]->ID, $s6->ID, "Page 6 associated correctly");
|
||||
}
|
||||
|
||||
public function testAddPageRelation()
|
||||
{
|
||||
$s1 = $this->objFromFixture('SiteTree', 's1');
|
||||
$s2 = $this->objFromFixture('SiteTree', 's2');
|
||||
$s3 = $this->objFromFixture('SiteTree', 's3');
|
||||
|
||||
$doc = new DMSDocument();
|
||||
$doc->Filename = "test file";
|
||||
$doc->Folder = "0";
|
||||
$doc->write();
|
||||
|
||||
$doc->addPage($s1);
|
||||
$doc->addPage($s2);
|
||||
$doc->addPage($s3);
|
||||
|
||||
$pages = $doc->Pages();
|
||||
$pagesArray = $pages->toArray();
|
||||
$this->assertEquals($pagesArray[0]->ID, $s1->ID, "Page 1 associated correctly");
|
||||
$this->assertEquals($pagesArray[1]->ID, $s2->ID, "Page 2 associated correctly");
|
||||
$this->assertEquals($pagesArray[2]->ID, $s3->ID, "Page 3 associated correctly");
|
||||
|
||||
$doc->removePage($s1);
|
||||
$pages = $doc->Pages();
|
||||
$pagesArray = $pages->toArray(); //page 1 is missing
|
||||
$this->assertEquals($pagesArray[0]->ID, $s2->ID, "Page 2 still associated correctly");
|
||||
$this->assertEquals($pagesArray[1]->ID, $s3->ID, "Page 3 still associated correctly");
|
||||
|
||||
$documents = $s2->Documents();
|
||||
$documentsArray = $documents->toArray();
|
||||
$this->assertDOSContains(array(array('Filename'=>$doc->Filename)), $documentsArray, "Document associated with page");
|
||||
|
||||
$doc->removeAllPages();
|
||||
$pages = $doc->Pages();
|
||||
$this->assertEquals($pages->Count(), 0, "All pages removed");
|
||||
|
||||
$documents = $s2->Documents();
|
||||
$documentsArray = $documents->toArray();
|
||||
$this->assertNotContains($doc, $documentsArray, "Document no longer associated with page");
|
||||
}
|
||||
|
||||
public function testDeletingPageWithAssociatedDocuments()
|
||||
{
|
||||
$s1 = $this->objFromFixture('SiteTree', 's1');
|
||||
$s2 = $this->objFromFixture('SiteTree', 's2');
|
||||
$s2->publish('Stage', 'Live');
|
||||
$s2ID = $s2->ID;
|
||||
|
||||
$doc = new DMSDocument();
|
||||
$doc->Filename = "delete test file";
|
||||
$doc->Folder = "0";
|
||||
$doc->write();
|
||||
|
||||
$doc->addPage($s1);
|
||||
$doc->addPage($s2);
|
||||
|
||||
$s1->delete();
|
||||
|
||||
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'", false);
|
||||
$this->assertEquals(
|
||||
$documents->Count(),
|
||||
'1',
|
||||
"Deleting one of the associated page doesn't affect the single document we created"
|
||||
);
|
||||
|
||||
$s2->delete();
|
||||
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'");
|
||||
$this->assertEquals(
|
||||
$documents->Count(),
|
||||
'1',
|
||||
"Deleting a page from draft stage doesn't delete the associated docs,"
|
||||
. "even if it's the last page they're associated with"
|
||||
);
|
||||
|
||||
$s2 = Versioned::get_one_by_stage('SiteTree', 'Live', sprintf('"SiteTree"."ID" = %d', $s2ID));
|
||||
$s2->doDeleteFromLive();
|
||||
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'");
|
||||
$this->assertEquals(
|
||||
$documents->Count(),
|
||||
'0',
|
||||
"However, deleting the live version of the last page that a document is "
|
||||
."associated with causes that document to be deleted as well"
|
||||
);
|
||||
}
|
||||
|
||||
public function testUnpublishPageWithAssociatedDocuments()
|
||||
{
|
||||
$s2 = $this->objFromFixture('SiteTree', 's2');
|
||||
$s2->publish('Stage', 'Live');
|
||||
$s2ID = $s2->ID;
|
||||
|
||||
$doc = new DMSDocument();
|
||||
$doc->Filename = "delete test file";
|
||||
$doc->Folder = "0";
|
||||
$doc->write();
|
||||
|
||||
$doc->addPage($s2);
|
||||
|
||||
$s2->doDeleteFromLive();
|
||||
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'");
|
||||
$this->assertEquals(
|
||||
$documents->Count(),
|
||||
'1',
|
||||
"Deleting a page from live stage doesn't delete the associated docs,"
|
||||
. "even if it's the last page they're associated with"
|
||||
);
|
||||
|
||||
$s2 = Versioned::get_one_by_stage('SiteTree', 'Stage', sprintf('"SiteTree"."ID" = %d', $s2ID));
|
||||
$s2->delete();
|
||||
$documents = DataObject::get("DMSDocument", "\"Filename\" = 'delete test file'");
|
||||
$this->assertEquals(
|
||||
$documents->Count(),
|
||||
'0',
|
||||
"However, deleting the draft version of the last page that a document is "
|
||||
."associated with causes that document to be deleted as well"
|
||||
);
|
||||
}
|
||||
|
||||
public function testDefaultDownloadBehabiourCMSFields() {
|
||||
$document = singleton('DMSDocument');
|
||||
Config::inst()->update('DMSDocument', 'default_download_behaviour', 'open');
|
||||
$cmsFields = $document->getCMSFields();
|
||||
|
@ -169,4 +15,341 @@ class DMSDocumentTest extends SapphireTest
|
|||
$cmsFields = $document->getCMSFields();
|
||||
$this->assertEquals('download', $cmsFields->dataFieldByName('DownloadBehavior')->Value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that related documents can be retrieved for a given DMS document
|
||||
*/
|
||||
public function testRelatedDocuments()
|
||||
{
|
||||
$document = $this->objFromFixture('DMSDocument', 'document_with_relations');
|
||||
$this->assertGreaterThan(0, $document->RelatedDocuments()->count());
|
||||
$this->assertEquals(
|
||||
array('test-file-file-doesnt-exist-1', 'test-file-file-doesnt-exist-2'),
|
||||
$document->getRelatedDocuments()->column('Filename')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the extensibility of getRelatedDocuments
|
||||
*/
|
||||
public function testGetRelatedDocumentsIsExtensible()
|
||||
{
|
||||
DMSDocument::add_extension('StubRelatedDocumentExtension');
|
||||
|
||||
$emptyDocument = new DMSDocument;
|
||||
$relatedDocuments = $emptyDocument->getRelatedDocuments();
|
||||
|
||||
$this->assertCount(1, $relatedDocuments);
|
||||
$this->assertSame('Extended', $relatedDocuments->first()->Filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the DMS Document CMS actions contains a grid field for managing related documents
|
||||
*/
|
||||
public function testDocumentHasCmsFieldForManagingRelatedDocuments()
|
||||
{
|
||||
$document = $this->objFromFixture('DMSDocument', 'document_with_relations');
|
||||
$gridField = $this->getRelatedDocumentsGridField($document);
|
||||
$this->assertInstanceOf('GridField', $gridField);
|
||||
|
||||
$gridFieldConfig = $gridField->getConfig();
|
||||
|
||||
$this->assertNotNull(
|
||||
'GridFieldAddExistingAutocompleter',
|
||||
$addExisting = $gridFieldConfig->getComponentByType('GridFieldAddExistingAutocompleter'),
|
||||
'Related documents GridField has an "add existing" autocompleter'
|
||||
);
|
||||
|
||||
$this->assertNull(
|
||||
$gridFieldConfig->getComponentByType('GridFieldAddNewButton'),
|
||||
'Related documents GridField does not have an "add new" button'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the DMS Document CMS Related and Versions fields are removed if user can't edit
|
||||
*/
|
||||
public function testDocumentHasNoCMSFieldsForManagingRelatedDocumentsIfCantEdit()
|
||||
{
|
||||
$this->logInWithPermission('another-user');
|
||||
$document = $this->objFromFixture('DMSDocument', 'doc-only-these-users');
|
||||
$gridField = $this->getRelatedDocumentsGridField($document);
|
||||
$this->assertNull($gridField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the related documents list does not include the current document itself
|
||||
*/
|
||||
public function testGetRelatedDocumentsForAutocompleter()
|
||||
{
|
||||
$document = $this->objFromFixture('DMSDocument', 'd1');
|
||||
$gridField = $this->getRelatedDocumentsGridField($document);
|
||||
$this->assertInstanceOf('GridField', $gridField);
|
||||
|
||||
$config = $gridField->getConfig();
|
||||
|
||||
$autocompleter = $config->getComponentByType('GridFieldAddExistingAutocompleter');
|
||||
$autocompleter->setResultsFormat('$Filename');
|
||||
|
||||
$jsonResult = $autocompleter->doSearch(
|
||||
$gridField,
|
||||
new SS_HTTPRequest('GET', '/', array('gridfield_relationsearch' => 'test'))
|
||||
);
|
||||
|
||||
$this->assertNotContains('test-file-file-doesnt-exist-1', $jsonResult);
|
||||
$this->assertContains('test-file-file-doesnt-exist-2', $jsonResult);
|
||||
$this->assertEquals(array('Title:PartialMatch', 'Filename:PartialMatch'), $autocompleter->getSearchFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GridField
|
||||
*/
|
||||
protected function getRelatedDocumentsGridField(DMSDocument $document)
|
||||
{
|
||||
$documentFields = $document->getCMSFields();
|
||||
/** @var FieldGroup $actions */
|
||||
$actions = $documentFields->fieldByName('ActionsPanel');
|
||||
|
||||
$gridField = null;
|
||||
foreach ($actions->getChildren() as $child) {
|
||||
/** @var FieldGroup $child */
|
||||
if ($gridField = $child->fieldByName('RelatedDocuments')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $gridField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that HTML is returned containing list items with action panel steps
|
||||
*/
|
||||
public function testGetActionTaskHtml()
|
||||
{
|
||||
$document = $this->objFromFixture('DMSDocument', 'd1');
|
||||
$document->addActionPanelTask('example', 'Example');
|
||||
|
||||
$result = $document->getActionTaskHtml();
|
||||
|
||||
$this->assertContains('<label class="left">Actions</label>', $result);
|
||||
$this->assertContains('<li class="ss-ui-button dmsdocument-action" data-panel="', $result);
|
||||
$this->assertContains('permission', $result);
|
||||
$this->assertContains('Example', $result);
|
||||
|
||||
$actions = array('example', 'embargo','find-usage');
|
||||
foreach ($actions as $action) {
|
||||
// Test remove with string
|
||||
$document->removeActionPanelTask($action);
|
||||
}
|
||||
$result = $document->getActionTaskHtml();
|
||||
|
||||
$this->assertNotContains('Example', $result);
|
||||
$this->assertNotContains('embargo', $result);
|
||||
$this->assertNotContains('find-usage', $result);
|
||||
// Positive test to see some action still remains
|
||||
$this->assertContains('find-references', $result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests whether the permissions fields are added
|
||||
*/
|
||||
public function testGetPermissionsActionPanel()
|
||||
{
|
||||
$result = $this->objFromFixture('DMSDocument', 'd1')->getPermissionsActionPanel();
|
||||
|
||||
$this->assertInstanceOf('CompositeField', $result);
|
||||
$this->assertNotNull($result->getChildren()->fieldByName('CanViewType'));
|
||||
$this->assertNotNull($result->getChildren()->fieldByName('ViewerGroups'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test view permissions
|
||||
*/
|
||||
public function testCanView()
|
||||
{
|
||||
/** @var DMSDocument $document */
|
||||
$document = $this->objFromFixture('DMSDocument', 'doc-logged-in-users');
|
||||
$this->logoutMember();
|
||||
// Logged out user test
|
||||
$this->assertFalse($document->canView());
|
||||
|
||||
// Logged in user test
|
||||
$adminID = $this->logInWithPermission();
|
||||
$admin = Member::get()->byID($adminID);
|
||||
$this->assertTrue($document->canView($admin));
|
||||
/** @var Member $member */
|
||||
$admin->logout();
|
||||
|
||||
// Check anyone
|
||||
$document = $this->objFromFixture('DMSDocument', 'doc-anyone');
|
||||
$this->assertTrue($document->canView());
|
||||
|
||||
// Check OnlyTheseUsers
|
||||
$document = $this->objFromFixture('DMSDocument', 'doc-only-these-users');
|
||||
$reportAdminID = $this->logInWithPermission('cable-guy');
|
||||
/** @var Member $reportAdmin */
|
||||
$reportAdmin = Member::get()->byID($reportAdminID);
|
||||
$this->assertFalse($document->canView($reportAdmin));
|
||||
// Add reportAdmin to group
|
||||
$reportAdmin->addToGroupByCode('content-author');
|
||||
$this->assertTrue($document->canView($reportAdmin));
|
||||
$reportAdmin->logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests edit permissions
|
||||
*/
|
||||
public function testCanEdit()
|
||||
{
|
||||
$this->logoutMember();
|
||||
|
||||
/** @var DMSDocument $document1 */
|
||||
$document1 = $this->objFromFixture('DMSDocument', 'doc-logged-in-users');
|
||||
|
||||
// Logged out user test
|
||||
$this->assertFalse($document1->canEdit());
|
||||
|
||||
//Logged in user test
|
||||
$contentAuthor = $this->objFromFixture('Member', 'editor');
|
||||
$this->assertTrue($document1->canEdit($contentAuthor));
|
||||
|
||||
// Check OnlyTheseUsers
|
||||
/** @var DMSDocument $document2 */
|
||||
$document2 = $this->objFromFixture('DMSDocument', 'doc-only-these-users');
|
||||
/** @var Member $cableGuy */
|
||||
$cableGuy = $this->objFromFixture('Member', 'non-editor');
|
||||
$this->assertFalse($document2->canEdit($cableGuy));
|
||||
|
||||
$cableGuy->addToGroupByCode('content-author');
|
||||
$this->assertTrue($document2->canEdit($cableGuy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests delete permissions
|
||||
*/
|
||||
public function testCanDelete()
|
||||
{
|
||||
$this->logoutMember();
|
||||
$document1 = $this->objFromFixture('DMSDocument', 'doc-logged-in-users');
|
||||
|
||||
// Logged out user test
|
||||
$this->assertFalse($document1->canDelete());
|
||||
|
||||
// Test editors can delete
|
||||
$contentAuthor = $this->objFromFixture('Member', 'editor');
|
||||
$this->assertTrue($document1->canDelete($contentAuthor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests create permission
|
||||
*/
|
||||
public function testCanCreate()
|
||||
{
|
||||
$this->logoutMember();
|
||||
$document1 = $this->objFromFixture('DMSDocument', 'doc-logged-in-users');
|
||||
$this->logInWithPermission('CMS_ACCESS_DMSDocumentAdmin');
|
||||
// Test CMS access can create
|
||||
$this->assertTrue($document1->canCreate());
|
||||
|
||||
$this->logoutMember();
|
||||
|
||||
// Test editors can create
|
||||
$contentAuthor = $this->objFromFixture('Member', 'editor');
|
||||
$this->assertTrue($document1->canCreate($contentAuthor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs out any active member
|
||||
*/
|
||||
protected function logoutMember()
|
||||
{
|
||||
if ($member = Member::currentUser()) {
|
||||
$member->logOut();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test permission denied reasons for documents
|
||||
*/
|
||||
public function testGetPermissionDeniedReason()
|
||||
{
|
||||
/** @var DMSDocument $document1 */
|
||||
$doc1 = $this->objFromFixture('DMSDocument', 'doc-logged-in-users');
|
||||
$this->assertContains('Please log in to view this document', $doc1->getPermissionDeniedReason());
|
||||
|
||||
/** @var DMSDocument $doc2 */
|
||||
$doc2 = $this->objFromFixture('DMSDocument', 'doc-only-these-users');
|
||||
$this->assertContains('You are not authorised to view this document', $doc2->getPermissionDeniedReason());
|
||||
|
||||
/** @var DMSDocument $doc3 */
|
||||
$doc3 = $this->objFromFixture('DMSDocument', 'doc-anyone');
|
||||
$this->assertEquals('', $doc3->getPermissionDeniedReason());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that all pages that a document belongs to (via many document sets) can be retrieved in one list
|
||||
*/
|
||||
public function testGetRelatedPages()
|
||||
{
|
||||
$document = $this->objFromFixture('DMSDocument', 'd1');
|
||||
$result = $document->getRelatedPages();
|
||||
$this->assertCount(3, $result, 'Document 1 is related to 3 Pages');
|
||||
$this->assertSame(array('s1', 's2', 's3'), $result->column('URLSegment'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the title is returned if it is set, otherwise the filename without ID
|
||||
*/
|
||||
public function testGetTitleOrFilenameWithoutId()
|
||||
{
|
||||
$d1 = $this->objFromFixture('DMSDocument', 'd1');
|
||||
$this->assertSame('test-file-file-doesnt-exist-1', $d1->getTitle());
|
||||
|
||||
$d2 = $this->objFromFixture('DMSDocument', 'd2');
|
||||
$this->assertSame('File That Doesn\'t Exist (Title)', $d2->getTitle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the folder a document's file is stored in can be retrieved, and that delete() will also delete
|
||||
* the file and the record
|
||||
*/
|
||||
public function testGetStorageFolderThenDelete()
|
||||
{
|
||||
Config::inst()->update('DMS', 'folder_name', 'assets/_unit-tests');
|
||||
|
||||
$document = DMS::inst()->storeDocument('dms/tests/DMS-test-lorum-file.pdf');
|
||||
$filename = $document->getStorageFolder() . '/' . $document->getFilename();
|
||||
|
||||
$this->assertTrue(file_exists($filename));
|
||||
$document->delete();
|
||||
$this->assertFalse($document->exists());
|
||||
$this->assertFalse(file_exists($filename));
|
||||
|
||||
DMSFilesystemTestHelper::delete('assets/_unit-tests');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the link contains an ID and URL slug
|
||||
*/
|
||||
public function testGetLink()
|
||||
{
|
||||
Config::inst()->update('DMS', 'folder_name', 'assets/_unit-tests');
|
||||
|
||||
$document = DMS::inst()->storeDocument('dms/tests/DMS-test-lorum-file.pdf');
|
||||
|
||||
$expected = '/dmsdocument/' . $document->ID . '-dms-test-lorum-file-pdf';
|
||||
$this->assertSame($expected, $document->Link());
|
||||
$this->assertSame($expected, $document->getLink());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the description can be returned in HTML format
|
||||
*/
|
||||
public function testGetDescriptionWithLineBreak()
|
||||
{
|
||||
$document = DMSDocument::create();
|
||||
$document->Description = "Line 1\nLine 2\nLine 3";
|
||||
$document->write();
|
||||
|
||||
$this->assertSame("Line 1<br />\nLine 2<br />\nLine 3", $document->getDescriptionWithLineBreak());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,7 @@
|
|||
<?php
|
||||
class DMSEmbargoTest extends SapphireTest
|
||||
{
|
||||
|
||||
public static $fixture_file = "dms/tests/dmsembargotest.yml";
|
||||
|
||||
public function tearDownOnce()
|
||||
{
|
||||
self::$is_running_test = true;
|
||||
|
||||
$d = DataObject::get("DMSDocument");
|
||||
foreach ($d as $d1) {
|
||||
$d1->delete();
|
||||
}
|
||||
$t = DataObject::get("DMSTag");
|
||||
foreach ($t as $t1) {
|
||||
$t1->delete();
|
||||
}
|
||||
|
||||
self::$is_running_test = $this->originalIsRunningTest;
|
||||
}
|
||||
protected static $fixture_file = 'dmsembargotest.yml';
|
||||
|
||||
public function createFakeHTTPRequest($id)
|
||||
{
|
||||
|
@ -29,33 +12,35 @@ class DMSEmbargoTest extends SapphireTest
|
|||
|
||||
public function testBasicEmbargo()
|
||||
{
|
||||
$oldDMSFolder = DMS::$dmsFolder;
|
||||
$oldTestMode = DMSDocument_Controller::$testMode;
|
||||
DMS::$dmsFolder = DMS_DIR; //sneakily setting the DMS folder to the folder where the test file lives
|
||||
Config::inst()->update('DMS', 'folder_name', 'assets/_unit-test-123');
|
||||
|
||||
$doc = new DMSDocument();
|
||||
$doc->Filename = "DMS-test-lorum-file.pdf";
|
||||
$doc->Folder = "tests";
|
||||
$doc = DMS::inst()->storeDocument('dms/tests/DMS-test-lorum-file.pdf');
|
||||
$doc->CanViewType = 'LoggedInUsers';
|
||||
$docID = $doc->write();
|
||||
|
||||
//fake a request for a document
|
||||
$controller = new DMSDocument_Controller();
|
||||
DMSDocument_Controller::$testMode = true;
|
||||
$result = $controller->index($this->createFakeHTTPRequest($docID));
|
||||
$this->assertEquals($doc->getFullPath(), $result, "Correct underlying file returned (in test mode)");
|
||||
$this->assertEquals($doc->getFullPath(), $result, 'Correct underlying file returned (in test mode)');
|
||||
|
||||
$doc->embargoIndefinitely();
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$result = $controller->index($this->createFakeHTTPRequest($docID));
|
||||
$this->assertEquals($doc->getFullPath(), $result, "Admins can still download embargoed files");
|
||||
$this->assertEquals($doc->getFullPath(), $result, 'Admins can still download embargoed files');
|
||||
|
||||
$this->logInWithPermission('random-user-group');
|
||||
$result = $controller->index($this->createFakeHTTPRequest($docID));
|
||||
$this->assertNotEquals($doc->getFullPath(), $result, "File no longer returned (in test mode) when switching to other user group");
|
||||
$this->assertNotEquals(
|
||||
$doc->getFullPath(),
|
||||
$result,
|
||||
'File no longer returned (in test mode) when switching to other user group'
|
||||
);
|
||||
|
||||
DMS::$dmsFolder = $oldDMSFolder;
|
||||
DMSDocument_Controller::$testMode = $oldTestMode;
|
||||
DMSFilesystemTestHelper::delete('assets/_unit-test-123');
|
||||
}
|
||||
|
||||
public function testEmbargoIndefinitely()
|
||||
|
@ -88,7 +73,7 @@ class DMSEmbargoTest extends SapphireTest
|
|||
$this->assertFalse($doc->isEmbargoed(), "Document is not embargoed");
|
||||
$this->assertTrue($doc->isExpired(), "Document is expired");
|
||||
|
||||
$expireTime = "2019-04-05 11:43:13";
|
||||
$expireTime = "2069-12-12 17:10:13";
|
||||
$doc->expireAtDate($expireTime);
|
||||
$this->assertFalse($doc->isHidden(), "Document is not hidden");
|
||||
$this->assertFalse($doc->isEmbargoed(), "Document is not embargoed");
|
||||
|
@ -129,7 +114,7 @@ class DMSEmbargoTest extends SapphireTest
|
|||
$this->assertFalse($doc->isEmbargoed(), "Document is not embargoed");
|
||||
$this->assertFalse($doc->isExpired(), "Document is not expired");
|
||||
|
||||
$embargoTime = "2019-04-05 11:43:13";
|
||||
$embargoTime = "2069-12-12 17:10:13";
|
||||
$doc->embargoUntilDate($embargoTime);
|
||||
$this->assertTrue($doc->isHidden(), "Document is hidden");
|
||||
$this->assertTrue($doc->isEmbargoed(), "Document is embargoed");
|
||||
|
@ -157,7 +142,7 @@ class DMSEmbargoTest extends SapphireTest
|
|||
$doc->Folder = "0";
|
||||
$dID = $doc->write();
|
||||
|
||||
$doc->addPage($s1);
|
||||
$s1->getDocumentSets()->first()->getDocuments()->add($doc);
|
||||
|
||||
$s1->publish('Stage', 'Live');
|
||||
$s1->doPublish();
|
||||
|
@ -192,7 +177,10 @@ class DMSEmbargoTest extends SapphireTest
|
|||
$s1->publish('Stage', 'Live');
|
||||
$s1->doPublish();
|
||||
$doc = DataObject::get_by_id("DMSDocument", $dID);
|
||||
$this->assertTrue($doc->isHidden(), "Document is still hidden because although the untilPublish flag is cleared, the indefinitely flag is still there");
|
||||
$this->assertTrue(
|
||||
$doc->isHidden(),
|
||||
"Document is still hidden because although the untilPublish flag is cleared, the indefinitely flag is there"
|
||||
);
|
||||
$this->assertTrue($doc->isEmbargoed(), "Document is embargoed");
|
||||
$this->assertFalse($doc->isExpired(), "Document is not expired");
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
class DMSFilesystemTestHelper
|
||||
{
|
||||
/**
|
||||
* Files that are added to the DMS asset directory by the DMS instance. They will be removed after running tests.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $dmsFiles = array('.htaccess', 'web.config');
|
||||
|
||||
/**
|
||||
* Deletes a directory and all files within it, or a file. Will automatically prepend the base path.
|
||||
*
|
||||
* This only work while a unit test is running for safety reasons.
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public static function delete($path)
|
||||
{
|
||||
if (!SapphireTest::is_running_test() || !file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = BASE_PATH . DIRECTORY_SEPARATOR . $path;
|
||||
if (is_dir($path)) {
|
||||
$files = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ($files as $fileinfo) {
|
||||
$action = $fileinfo->isDir() ? 'rmdir' : 'unlink';
|
||||
$action($fileinfo->getRealPath());
|
||||
}
|
||||
|
||||
rmdir($path);
|
||||
} else {
|
||||
unlink($path);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/**
|
||||
* Tests DMS shortcode linking functionality.
|
||||
*
|
||||
* @package dms
|
||||
* @subpackage tests
|
||||
*/
|
||||
class DMSShortcodeHandlerTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'dmstest.yml';
|
||||
|
||||
public function testShortcodeOperation()
|
||||
{
|
||||
Config::inst()->update('DMS', 'folder_name', 'assets/_unit-test-123');
|
||||
|
||||
$file = 'dms/tests/DMS-test-lorum-file.pdf';
|
||||
$document = DMS::inst()->storeDocument($file);
|
||||
|
||||
$result = ShortcodeParser::get('default')->parse(sprintf(
|
||||
'<p><a href="[dms_document_link id=\'%d\']">Document</a></p>',
|
||||
$document->ID
|
||||
));
|
||||
|
||||
$value = Injector::inst()->create('HTMLValue', $result);
|
||||
$link = $value->query('//a')->item(0);
|
||||
|
||||
$this->assertStringEndsWith(
|
||||
'/dmsdocument/' . $document->ID . '-dms-test-lorum-file-pdf',
|
||||
$link->getAttribute('href')
|
||||
);
|
||||
$this->assertEquals($document->getExtension(), $link->getAttribute('data-ext'));
|
||||
$this->assertEquals($document->getFileSizeFormatted(), $link->getAttribute('data-size'));
|
||||
|
||||
DMSFilesystemTestHelper::delete('assets/_unit-test-123');
|
||||
}
|
||||
|
||||
/**
|
||||
* When the document is valid, the correct arguments are provided and some content is given, the content should
|
||||
* be parsed and added into an anchor to the document
|
||||
*/
|
||||
public function testShortcodeWithContentReturnsParsedContentInLink()
|
||||
{
|
||||
$document = $this->objFromFixture('DMSDocument', 'd1');
|
||||
$arguments = array('id' => $document->ID);
|
||||
$result = DMSShortcodeHandler::handle($arguments, 'Some content', ShortcodeParser::get('default'), '');
|
||||
|
||||
$this->assertSame(
|
||||
'<a href="/dmsdocument/' . $document->ID . '-test-file-file-doesnt-exist-1">Some content</a>',
|
||||
$result
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* An error page link should be returned if the arguments are not valid, empty or the document is not available etc.
|
||||
*
|
||||
* This only applies when an error page with a 404 error code exists.
|
||||
*/
|
||||
public function testReturnErrorPageWhenIdIsEmpty()
|
||||
{
|
||||
ErrorPage::create(array('URLSegment' => 'testing', 'ErrorCode' => '404'))->write();
|
||||
$result = DMSShortcodeHandler::handle(array(), '', ShortcodeParser::get('default'), '');
|
||||
$this->assertContains('testing', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* When invalid or no data is available to return from the arguments and no error page exists to use for a link,
|
||||
* return a blank string
|
||||
*/
|
||||
public function testReturnEmptyStringWhenNoErrorPageExistsAndIdIsEmpty()
|
||||
{
|
||||
$this->assertSame('', DMSShortcodeHandler::handle(array(), '', ShortcodeParser::get('default'), ''));
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Tests DMS shortcode linking functionality.
|
||||
*
|
||||
* @package dms
|
||||
* @subpackage tests
|
||||
*/
|
||||
class DMSShortcodeTest extends SapphireTest
|
||||
{
|
||||
|
||||
public function testShortcodeOperation()
|
||||
{
|
||||
$file = 'dms/tests/DMS-test-lorum-file.pdf';
|
||||
$document = DMS::inst()->storeDocument($file);
|
||||
|
||||
$result = ShortcodeParser::get('default')->parse(sprintf(
|
||||
'<p><a href="[dms_document_link id=\'%d\']">Document</a></p>', $document->ID
|
||||
));
|
||||
|
||||
$value = Injector::inst()->create('HTMLValue', $result);
|
||||
$link = $value->query('//a')->item(0);
|
||||
|
||||
$this->assertStringEndsWith("/dmsdocument/$document->ID", $link->getAttribute('href'));
|
||||
$this->assertEquals($document->getExtension(), $link->getAttribute('data-ext'));
|
||||
$this->assertEquals($document->getFileSizeFormatted(), $link->getAttribute('data-size'));
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
<?php
|
||||
class DMSTagTest extends SapphireTest
|
||||
{
|
||||
|
||||
public function tearDownOnce()
|
||||
{
|
||||
self::$is_running_test = true;
|
||||
|
||||
$d = DataObject::get("DMSDocument");
|
||||
foreach ($d as $d1) {
|
||||
$d1->delete();
|
||||
}
|
||||
$t = DataObject::get("DMSTag");
|
||||
foreach ($t as $t1) {
|
||||
$t1->delete();
|
||||
}
|
||||
|
||||
self::$is_running_test = $this->originalIsRunningTest;
|
||||
}
|
||||
|
||||
public function testAddingTags()
|
||||
{
|
||||
$doc = new DMSDocument();
|
||||
$doc->Filename = "test file";
|
||||
$doc->Folder = "0";
|
||||
$doc->write();
|
||||
|
||||
$doc->addTag("fruit", "banana");
|
||||
$doc->addTag("fruit", "orange");
|
||||
$doc->addTag("fruit", "apple");
|
||||
$doc->addTag("company", "apple");
|
||||
$doc->addTag("company", "SilverStripe");
|
||||
|
||||
$fruits = $doc->getTagsList("fruit");
|
||||
$this->assertNotNull($fruits, "Something returned for fruit tags");
|
||||
$this->assertEquals(count($fruits), 3, "3 fruit tags returned");
|
||||
$this->assertTrue(in_array("banana", $fruits), "correct fruit tags returned");
|
||||
|
||||
//sneakily create another document and link one of the tags to that, too
|
||||
$doc2 = new DMSDocument();
|
||||
$doc2->Filename = "sneaky file";
|
||||
$doc2->Folder = "0";
|
||||
$doc2->write();
|
||||
$doc2->addTag("fruit", "banana");
|
||||
|
||||
$fruits = $doc2->getTagsList("fruit");
|
||||
$this->assertNotNull($fruits, "Something returned for fruit tags");
|
||||
$this->assertEquals(count($fruits), 1, "Only 1 fruit tags returned");
|
||||
|
||||
//tidy up by deleting all tags from doc 1 (But the banana fruit tag should remain)
|
||||
$doc->removeAllTags();
|
||||
|
||||
//banana fruit remains
|
||||
$fruits = $doc2->getTagsList("fruit");
|
||||
$this->assertNotNull($fruits, "Something returned for fruit tags");
|
||||
$this->assertEquals(count($fruits), 1, "Only 1 fruit tags returned");
|
||||
|
||||
$tags = DataObject::get("DMSTag");
|
||||
$this->assertEquals($tags->Count(), 1, "A single DMS tag objects remain after deletion of all tags on doc1");
|
||||
|
||||
//delete all tags off doc2 to complete the tidy up
|
||||
$doc2->removeAllTags();
|
||||
|
||||
$tags = DataObject::get("DMSTag");
|
||||
$this->assertEquals($tags->Count(), 0, "No DMS tag objects remain after deletion");
|
||||
}
|
||||
|
||||
public function testRemovingTags()
|
||||
{
|
||||
$doc = new DMSDocument();
|
||||
$doc->Filename = "test file";
|
||||
$doc->Folder = "0";
|
||||
$doc->write();
|
||||
|
||||
$doc->addTag("fruit", "banana");
|
||||
$doc->addTag("fruit", "orange");
|
||||
$doc->addTag("fruit", "apple");
|
||||
$doc->addTag("company", "apple");
|
||||
$doc->addTag("company", "SilverStripe");
|
||||
|
||||
$companies = $doc->getTagsList("company");
|
||||
$this->assertNotNull($companies, "Companies returned before deletion");
|
||||
$this->assertEquals(count($companies), 2, "Two companies returned before deletion");
|
||||
|
||||
//delete an entire category
|
||||
$doc->removeTag("company");
|
||||
|
||||
$companies = $doc->getTagsList("company");
|
||||
$this->assertNull($companies, "All companies deleted");
|
||||
|
||||
$fruit = $doc->getTagsList("fruit");
|
||||
$this->assertEquals(count($fruit), 3, "Three fruits returned before deletion");
|
||||
|
||||
//delete a single tag
|
||||
$doc->removeTag("fruit", "apple");
|
||||
|
||||
$fruit = $doc->getTagsList("fruit");
|
||||
$this->assertEquals(count($fruit), 2, "Two fruits returned after deleting one");
|
||||
|
||||
//delete a single tag
|
||||
$doc->removeTag("fruit", "orange");
|
||||
|
||||
$fruit = $doc->getTagsList("fruit");
|
||||
$this->assertEquals(count($fruit), 1, "One fruits returned after deleting two");
|
||||
|
||||
//nothing happens when deleting tag that doesn't exist
|
||||
$doc->removeTag("fruit", "jellybean");
|
||||
|
||||
$fruit = $doc->getTagsList("fruit");
|
||||
$this->assertEquals(count($fruit), 1, "One fruits returned after attempting to delete non-existent fruit");
|
||||
|
||||
//delete the last fruit
|
||||
$doc->removeTag("fruit", "banana");
|
||||
|
||||
$fruit = $doc->getTagsList("fruit");
|
||||
$this->assertNull($fruit, "All fruits deleted");
|
||||
|
||||
$tags = DataObject::get("DMSTag");
|
||||
$this->assertEquals($tags->Count(), 0, "No DMS tag objects remain after deletion");
|
||||
}
|
||||
}
|
|
@ -1,148 +1,183 @@
|
|||
<?php
|
||||
class DMSTest extends FunctionalTest
|
||||
{
|
||||
protected static $fixture_file = 'dmstest.yml';
|
||||
|
||||
/**
|
||||
* Stub PDF files for testing
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $testFile = 'dms/tests/DMS-test-lorum-file.pdf';
|
||||
public static $testFile2 = 'dms/tests/DMS-test-document-2.pdf';
|
||||
|
||||
//store values to reset back to after this test runs
|
||||
public static $dmsFolderOld;
|
||||
public static $dmsFolderSizeOld;
|
||||
/**
|
||||
* The test folder to write assets into
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $testDmsPath = 'assets/_dms-assets-test-1234';
|
||||
|
||||
/**
|
||||
* @var DMSInterace
|
||||
*/
|
||||
protected $dms;
|
||||
|
||||
/**
|
||||
* Use a test DMS folder, so we don't overwrite the live one, and clear it out in case of previous broken tests
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
self::$dmsFolderOld = DMS::$dmsFolder;
|
||||
self::$dmsFolderSizeOld = DMS::$dmsFolderSize;
|
||||
|
||||
//use a test DMS folder, so we don't overwrite the live one
|
||||
DMS::$dmsFolder = 'dms-assets-test-1234';
|
||||
|
||||
//clear out the test folder (in case a broken test doesn't delete it)
|
||||
$this->delete(BASE_PATH . DIRECTORY_SEPARATOR . 'dms-assets-test-1234');
|
||||
Config::inst()->update('DMS', 'folder_name', $this->testDmsPath);
|
||||
DMSFilesystemTestHelper::delete($this->testDmsPath);
|
||||
$this->dms = DMS::inst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the test folder after the test runs
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
self::$is_running_test = true;
|
||||
|
||||
$d = DataObject::get("DMSDocument");
|
||||
foreach ($d as $d1) {
|
||||
$d1->delete();
|
||||
}
|
||||
$t = DataObject::get("DMSTag");
|
||||
foreach ($t as $t1) {
|
||||
$t1->delete();
|
||||
}
|
||||
|
||||
//delete the test folder after the test runs
|
||||
$this->delete(BASE_PATH . DIRECTORY_SEPARATOR . 'dms-assets-test-1234');
|
||||
|
||||
//set the old DMS folder back again
|
||||
DMS::$dmsFolder = self::$dmsFolderOld;
|
||||
DMS::$dmsFolderSize = self::$dmsFolderSizeOld;
|
||||
|
||||
self::$is_running_test = $this->originalIsRunningTest;
|
||||
DMSFilesystemTestHelper::delete($this->testDmsPath);
|
||||
}
|
||||
|
||||
public function delete($path)
|
||||
{
|
||||
if (file_exists($path) || is_dir($path)) {
|
||||
$it = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($path),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
foreach ($it as $file) {
|
||||
if (in_array($file->getBasename(), array('.', '..'))) {
|
||||
continue;
|
||||
} elseif ($file->isDir()) {
|
||||
rmdir($file->getPathname());
|
||||
} elseif ($file->isFile() || $file->isLink()) {
|
||||
unlink($file->getPathname());
|
||||
}
|
||||
}
|
||||
rmdir($path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testDMSStorage()
|
||||
{
|
||||
$dms = DMS::inst();
|
||||
|
||||
$file = self::$testFile;
|
||||
$document = $dms->storeDocument($file);
|
||||
$document = $this->dms->storeDocument($file);
|
||||
|
||||
$this->assertNotNull($document, "Document object created");
|
||||
$this->assertTrue(file_exists(DMS::get_dms_path() . DIRECTORY_SEPARATOR . $document->Folder . DIRECTORY_SEPARATOR . $document->Filename), "Document file copied into DMS folder");
|
||||
|
||||
//$title = $document->getTag('title');
|
||||
$this->assertTrue(
|
||||
file_exists(
|
||||
DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . $document->Folder
|
||||
. DIRECTORY_SEPARATOR . $document->Filename
|
||||
),
|
||||
"Document file copied into DMS folder"
|
||||
);
|
||||
}
|
||||
|
||||
public function testDMSFolderSpanning()
|
||||
{
|
||||
DMS::$dmsFolderSize = 5;
|
||||
$dms = DMS::inst();
|
||||
|
||||
Config::inst()->update('DMS', 'folder_size', 5);
|
||||
$file = self::$testFile;
|
||||
|
||||
$documents = array();
|
||||
for ($i = 0; $i <= 16; $i++) {
|
||||
$document = $dms->storeDocument($file);
|
||||
$document = $this->dms->storeDocument($file);
|
||||
$this->assertNotNull($document, "Document object created on run number: $i");
|
||||
$this->assertTrue(file_exists($document->getFullPath()));
|
||||
$documents[] = $document;
|
||||
}
|
||||
|
||||
//test document objects have their folders set
|
||||
// Test document objects have their folders set
|
||||
$folders = array();
|
||||
for ($i = 0; $i <= 16; $i++) {
|
||||
$folderName = $documents[$i]->Folder;
|
||||
$this->assertTrue(strpos($documents[$i]->getFullPath(), DIRECTORY_SEPARATOR . $folderName . DIRECTORY_SEPARATOR) !== false, "Correct folder name for the documents. Document path contains reference to folder name '$folderName'");
|
||||
$this->assertTrue(
|
||||
strpos($documents[$i]->getFullPath(), DIRECTORY_SEPARATOR . $folderName . DIRECTORY_SEPARATOR) !== false,
|
||||
"Correct folder name for the documents. Document path contains reference to folder name '$folderName'"
|
||||
);
|
||||
$folders[] = $folderName;
|
||||
}
|
||||
|
||||
//test we created 4 folder to contain the 17 files
|
||||
// Test we created 4 folder to contain the 17 files
|
||||
foreach ($folders as $f) {
|
||||
$this->assertTrue(is_dir(DMS::get_dms_path() . DIRECTORY_SEPARATOR . $f), "Document folder '$f' exists");
|
||||
$this->assertTrue(
|
||||
is_dir(DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . $f),
|
||||
"Document folder '$f' exists"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testReplaceDocument()
|
||||
{
|
||||
$dms = DMS::inst();
|
||||
|
||||
//store the first document
|
||||
$document = $dms->storeDocument(self::$testFile);
|
||||
// Store the first document
|
||||
$document = $this->dms->storeDocument(self::$testFile);
|
||||
$document->Title = "My custom title";
|
||||
$document->Description = "My custom description";
|
||||
$document->write();
|
||||
|
||||
//then overwrite with a second document
|
||||
// Then overwrite with a second document
|
||||
$document = $document->replaceDocument(self::$testFile2);
|
||||
|
||||
$this->assertNotNull($document, "Document object created");
|
||||
$this->assertTrue(file_exists(DMS::get_dms_path() . DIRECTORY_SEPARATOR . $document->Folder . DIRECTORY_SEPARATOR . $document->Filename), "Document file copied into DMS folder");
|
||||
$this->assertContains("DMS-test-document-2", $document->Filename, "Original document filename is contain in the new filename");
|
||||
$this->assertTrue(
|
||||
file_exists(
|
||||
DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . $document->Folder
|
||||
. DIRECTORY_SEPARATOR . $document->Filename
|
||||
),
|
||||
"Document file copied into DMS folder"
|
||||
);
|
||||
$this->assertContains(
|
||||
"DMS-test-document-2",
|
||||
$document->Filename,
|
||||
"Original document filename is contain in the new filename"
|
||||
);
|
||||
$this->assertEquals("My custom title", $document->Title, "Custom title not modified");
|
||||
$this->assertEquals("My custom description", $document->Description, "Custom description not modified");
|
||||
}
|
||||
|
||||
public function testDownloadDocument()
|
||||
/**
|
||||
* Test that documents can be returned by a given page
|
||||
*/
|
||||
public function testGetByPageWithoutEmbargoes()
|
||||
{
|
||||
// $dms = DMS::inst();
|
||||
//
|
||||
// //store the first document
|
||||
// $document = $dms->storeDocument(self::$testFile);
|
||||
// $link = $document->getLink();
|
||||
//
|
||||
// Debug::Show($link);
|
||||
// $d=new DMSDocument_Controller();
|
||||
// $response = $d->index(new SS_HTTPRequest('GET',$link,array("ID"=>$document->ID)));
|
||||
// //$response = $this->get($link);
|
||||
// Debug::show($response);
|
||||
$pageWithEmbargoes = $this->objFromFixture('SiteTree', 's3');
|
||||
$documents = $this->dms->getByPage($pageWithEmbargoes);
|
||||
// Fixture: 6 documents in set, 1 is embargoed
|
||||
$this->assertCount(5, $documents, 'Embargoed documents are excluded by default');
|
||||
$this->assertContainsOnlyInstancesOf('DMSDocument', $documents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that embargoed documents are excluded from getByPage
|
||||
*/
|
||||
public function testGetByPageWithEmbargoedDocuments()
|
||||
{
|
||||
$pageWithEmbargoes = $this->objFromFixture('SiteTree', 's3');
|
||||
$documents = $this->dms->getByPage($pageWithEmbargoes, true);
|
||||
// Fixture: 6 documents in set, 1 is embargoed
|
||||
$this->assertCount(6, $documents, 'Embargoed documents can be included');
|
||||
$this->assertContainsOnlyInstancesOf('DMSDocument', $documents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the shortcode handler key is configurable
|
||||
*/
|
||||
public function testShortcodeHandlerKeyIsConfigurable()
|
||||
{
|
||||
Config::inst()->update('DMS', 'shortcode_handler_key', 'testing');
|
||||
$this->assertSame('testing', DMS::inst()->getShortcodeHandlerKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that document sets can be retrieved for a given page
|
||||
*/
|
||||
public function testGetDocumentSetsByPage()
|
||||
{
|
||||
$page = $this->objFromFixture('SiteTree', 's1');
|
||||
$sets = $this->dms->getDocumentSetsByPage($page);
|
||||
$this->assertCount(2, $sets);
|
||||
$this->assertContainsOnlyInstancesOf('DMSDocumentSet', $sets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that assets/* folders are not included in filesystem sync operations
|
||||
*/
|
||||
public function testFolderExcludedFromFilesystemSync()
|
||||
{
|
||||
// Undo setup config changes
|
||||
Config::unnest();
|
||||
Config::nest();
|
||||
|
||||
$result = Filesystem::config()->get('sync_blacklisted_patterns');
|
||||
$folderName = substr(DMS::config()->get('folder_name'), 7);
|
||||
$this->assertContains('/^' . $folderName . '$/i', $result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,82 +1,75 @@
|
|||
<?php
|
||||
class DMSVersioningTest extends SapphireTest
|
||||
{
|
||||
protected $usesDatabase = true;
|
||||
|
||||
/**
|
||||
* Stub PDF files for testing
|
||||
* @var string
|
||||
*/
|
||||
public static $testFile = 'dms/tests/DMS-test-lorum-file.pdf';
|
||||
public static $testFile2 = 'dms/tests/DMS-test-document-2.pdf';
|
||||
|
||||
//store values to reset back to after this test runs
|
||||
public static $dmsFolderOld;
|
||||
public static $dmsFolderSizeOld;
|
||||
/**
|
||||
* The test folder to write assets into
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $testDmsPath = 'assets/_dms-assets-test-versions';
|
||||
|
||||
/**
|
||||
* Store values to reset back to after this test runs
|
||||
*/
|
||||
public static $dmsEnableVersionsOld;
|
||||
|
||||
/**
|
||||
* Use a test DMS folder, so we don't overwrite the live one, and clear out the test folder (in case a broken
|
||||
* test doesn't delete it)
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
self::$dmsFolderOld = DMS::$dmsFolder;
|
||||
self::$dmsFolderSizeOld = DMS::$dmsFolderSize;
|
||||
self::$dmsEnableVersionsOld = DMSDocument_versions::$enable_versions;
|
||||
DMSDocument_versions::$enable_versions = true;
|
||||
|
||||
//use a test DMS folder, so we don't overwrite the live one
|
||||
DMS::$dmsFolder = 'dms-assets-test-versions';
|
||||
|
||||
//clear out the test folder (in case a broken test doesn't delete it)
|
||||
$this->delete(BASE_PATH . DIRECTORY_SEPARATOR . 'dms-assets-test-versions');
|
||||
Config::inst()->update('DMS', 'folder_name', $this->testDmsPath);
|
||||
DMSFilesystemTestHelper::delete($this->testDmsPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the test folder after the tests run
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function tearDown()
|
||||
{
|
||||
$d = DataObject::get("DMSDocument");
|
||||
foreach ($d as $d1) {
|
||||
$d1->delete();
|
||||
}
|
||||
$t = DataObject::get("DMSTag");
|
||||
foreach ($t as $t1) {
|
||||
$t1->delete();
|
||||
}
|
||||
|
||||
//delete the test folder after the test runs
|
||||
$this->delete(BASE_PATH . DIRECTORY_SEPARATOR . 'dms-assets-test-versions');
|
||||
|
||||
parent::tearDown();
|
||||
|
||||
//set the old DMS folder back again
|
||||
DMS::$dmsFolder = self::$dmsFolderOld;
|
||||
DMS::$dmsFolderSize = self::$dmsFolderSizeOld;
|
||||
DMSFilesystemTestHelper::delete($this->testDmsPath);
|
||||
|
||||
// Set the old DMS folder back again
|
||||
DMSDocument_versions::$enable_versions = self::$dmsEnableVersionsOld;
|
||||
}
|
||||
|
||||
public function delete($path)
|
||||
{
|
||||
if (file_exists($path) || is_dir($path)) {
|
||||
$it = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($path),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
foreach ($it as $file) {
|
||||
if (in_array($file->getBasename(), array('.', '..'))) {
|
||||
continue;
|
||||
} elseif ($file->isDir()) {
|
||||
rmdir($file->getPathname());
|
||||
} elseif ($file->isFile() || $file->isLink()) {
|
||||
unlink($file->getPathname());
|
||||
}
|
||||
}
|
||||
rmdir($path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testDMSVersionStorage()
|
||||
{
|
||||
$this->markTestSkipped('Needs re-implementation, this test is not consistent.');
|
||||
|
||||
$dms = DMS::inst();
|
||||
|
||||
$document = $dms->storeDocument(self::$testFile);
|
||||
|
||||
$this->assertNotNull($document, "Document object created");
|
||||
$this->assertTrue(file_exists(DMS::get_dms_path() . DIRECTORY_SEPARATOR . $document->Folder . DIRECTORY_SEPARATOR . $document->Filename), "Document file copied into DMS folder");
|
||||
$this->assertTrue(
|
||||
file_exists(
|
||||
DMS::inst()->getStoragePath() . DIRECTORY_SEPARATOR . $document->Folder
|
||||
. DIRECTORY_SEPARATOR . $document->Filename
|
||||
),
|
||||
"Document file copied into DMS folder"
|
||||
);
|
||||
|
||||
$document->replaceDocument(self::$testFile2);
|
||||
$document->replaceDocument(self::$testFile);
|
||||
|
|
|
@ -1,26 +1,25 @@
|
|||
<?php
|
||||
class ShortCodeRelationFinderTest extends SapphireTest
|
||||
{
|
||||
|
||||
public static $fixture_file = array(
|
||||
'dms/tests/dmstest.yml'
|
||||
);
|
||||
protected static $fixture_file = 'dmstest.yml';
|
||||
|
||||
public function testFindInRate()
|
||||
{
|
||||
Config::inst()->update('DMS', 'shortcode_handler_key', 'dms_document_link');
|
||||
|
||||
$d1 = $this->objFromFixture('DMSDocument', 'd1');
|
||||
$d2 = $this->objFromFixture('DMSDocument', 'd2');
|
||||
|
||||
$page1 = new SiteTree();
|
||||
$page1->Content = 'Condition: <a title="document test 1" href="[dms_document_link,id='.$d1->ID.']">';
|
||||
$page1->Content = 'Condition: <a title="document test 1" href="[dms_document_link,id=' . $d1->ID . ']">';
|
||||
$page1ID = $page1->write();
|
||||
|
||||
$page2 = new SiteTree();
|
||||
$page2->Content = 'Condition: <a title="document test 2" href="[dms_document_link,id='.$d2->ID.']">';
|
||||
$page2->Content = 'Condition: <a title="document test 2" href="[dms_document_link,id=' . $d2->ID . ']">';
|
||||
$page2ID = $page2->write();
|
||||
|
||||
$page3 = new SiteTree();
|
||||
$page3->Content = 'Condition: <a title="document test 1" href="[dms_document_link,id='.$d1->ID.']">';
|
||||
$page3->Content = 'Condition: <a title="document test 1" href="[dms_document_link,id=' . $d1->ID . ']">';
|
||||
$page3ID = $page3->write();
|
||||
|
||||
$finder = new ShortCodeRelationFinder();
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class StubRelatedDocumentExtension
|
||||
*
|
||||
* @package dms
|
||||
*/
|
||||
class StubRelatedDocumentExtension extends DataExtension implements TestOnly
|
||||
{
|
||||
/**
|
||||
* For method {@link DMSDocument::getRelatedDocuments}
|
||||
*
|
||||
* @param ArrayList $relatedDocuments
|
||||
* @return ArrayList
|
||||
*/
|
||||
public function updateRelatedDocuments($relatedDocuments)
|
||||
{
|
||||
$relatedDocuments->push($this->getFakeDocument());
|
||||
return $relatedDocuments;
|
||||
}
|
||||
|
||||
/**
|
||||
* For method {@link DMSDocumentSet::getDocuments}
|
||||
*
|
||||
* @param ArrayList $relatedDocuments
|
||||
* @return ArrayList
|
||||
*/
|
||||
public function updateDocuments($documents)
|
||||
{
|
||||
$documents->push($this->getFakeDocument());
|
||||
return $documents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a dummy document for testing purposes
|
||||
*
|
||||
* @return DMSDocument
|
||||
*/
|
||||
protected function getFakeDocument()
|
||||
{
|
||||
$fakeDocument = new DMSDocument;
|
||||
$fakeDocument->Filename = 'Extended';
|
||||
return $fakeDocument;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
class DMSDocumentAddControllerTest extends FunctionalTest
|
||||
{
|
||||
protected static $fixture_file = 'dms/tests/dmstest.yml';
|
||||
|
||||
/**
|
||||
* @var DMSDocumentAddController
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->logInWithPermission();
|
||||
$this->controller = new DMSDocumentAddController;
|
||||
$this->controller->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that if no ID is provided then a SiteTree singleton is returned (which will not have an ID). If one is
|
||||
* provided then it should be loaded from the database via versioning.
|
||||
*/
|
||||
public function testCurrentPageReturnsSiteTree()
|
||||
{
|
||||
$page = $this->objFromFixture('SiteTree', 's1');
|
||||
|
||||
$this->assertInstanceOf('SiteTree', $this->controller->currentPage());
|
||||
$this->assertEmpty($this->controller->currentPage()->ID);
|
||||
$this->controller->setRequest(new SS_HTTPRequest('GET', '/', array('page_id' => $page->ID)));
|
||||
$this->assertEquals($page->ID, $this->controller->currentPage()->ID, 'Specified page is loaded and returned');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that if no "dsid" is given a singleton is returned (which will not have an ID). If one is provided
|
||||
* it should be loaded from the database
|
||||
*/
|
||||
public function testGetCurrentDocumentSetReturnsDocumentSet()
|
||||
{
|
||||
$set = $this->objFromFixture('DMSDocumentSet', 'ds1');
|
||||
|
||||
$this->assertInstanceOf('DMSDocumentSet', $this->controller->getCurrentDocumentSet());
|
||||
$this->assertEmpty($this->controller->getCurrentDocumentSet()->ID, 'Singleton does not have an ID');
|
||||
$this->controller->setRequest(new SS_HTTPRequest('GET', '/', array('dsid' => $set->ID)));
|
||||
$this->assertEquals($set->ID, $this->controller->getCurrentDocumentSet()->ID, 'Specified document set is returned');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that extra allowed extensions are merged into the default upload field allowed extensions
|
||||
*/
|
||||
public function testGetAllowedExtensions()
|
||||
{
|
||||
Config::inst()->remove('File', 'allowed_extensions');
|
||||
Config::inst()->update('File', 'allowed_extensions', array('jpg', 'gif'));
|
||||
$this->assertSame(array('jpg', 'gif'), $this->controller->getAllowedExtensions());
|
||||
|
||||
Config::inst()->update('DMSDocumentAddController', 'allowed_extensions', array('php', 'php5'));
|
||||
$this->assertSame(array('jpg', 'gif', 'php', 'php5'), $this->controller->getAllowedExtensions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the back link will be the document set that a file is uploaded into if relevant, otherwise the model
|
||||
* admin that it was uploaded from
|
||||
*/
|
||||
public function testBacklink()
|
||||
{
|
||||
// No page ID and no document set ID
|
||||
$this->assertContains('admin/documents', $this->controller->Backlink());
|
||||
|
||||
// No page ID, has document set ID
|
||||
$request = new SS_HTTPRequest('GET', '/', array('dsid' => 123));
|
||||
$this->controller->setRequest($request);
|
||||
$this->assertContains('EditForm', $this->controller->Backlink());
|
||||
$this->assertContains('123', $this->controller->Backlink());
|
||||
|
||||
// Has page ID and document set ID
|
||||
$request = new SS_HTTPRequest('GET', '/', array('dsid' => 123, 'page_id' => 234));
|
||||
$this->controller->setRequest($request);
|
||||
$this->assertContains('admin/pages', $this->controller->Backlink());
|
||||
$this->assertContains('123', $this->controller->Backlink());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the document autocomplete endpoint returns JSON, matching on ID, title or filename (case insensitive)
|
||||
*/
|
||||
public function testDocumentAutocomplete()
|
||||
{
|
||||
$result = (string) $this->get('admin/pages/adddocument/documentautocomplete?term=EXIST')->getBody();
|
||||
$this->assertJson($result, 'Autocompleter should return JSON');
|
||||
$this->assertContains("File That Doesn't Exist (Title)", $result);
|
||||
$this->assertContains('test-file-file-doesnt-exist-1', $result);
|
||||
$this->assertNotContains('doc-logged-in-users', $result);
|
||||
|
||||
$document = $this->objFromFixture('DMSDocument', 'd2');
|
||||
$result = (string) $this->get('admin/pages/adddocument/documentautocomplete?term=' . $document->ID)->getBody();
|
||||
$this->assertContains($document->ID . " - File That Doesn't Exist (Title)", $result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
class DMSDocumentAddExistingFieldTest extends SapphireTest
|
||||
{
|
||||
/**
|
||||
* The constructor should create a tree dropdown field
|
||||
*/
|
||||
public function testFieldContainsTreeDropdownField()
|
||||
{
|
||||
$field = new DMSDocumentAddExistingField('Test', 'Test');
|
||||
$this->assertContainsOnlyInstancesOf('TreeDropdownField', $field->getChildren());
|
||||
$this->assertSame('PageSelector', $field->getChildren()->first()->getName());
|
||||
}
|
||||
|
||||
public function testSetAndGetRecord()
|
||||
{
|
||||
$record = new DMSDocumentSet;
|
||||
$field = new DMSDocumentAddExistingField('Test');
|
||||
$field->setRecord($record);
|
||||
$this->assertSame($record, $field->getRecord());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
class DMSDocumentAdminTest extends FunctionalTest
|
||||
{
|
||||
protected static $fixture_file = 'DMSDocumentAdminTest.yml';
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the default "add new" and "edit" buttons are gone, and replaced with our customised version of it
|
||||
*/
|
||||
public function testGridFieldHasCustomisedButtons()
|
||||
{
|
||||
$modelAdmin = new DMSDocumentAdmin;
|
||||
$modelAdmin->init();
|
||||
|
||||
$form = $modelAdmin->getEditForm();
|
||||
$gridFieldConfig = $form->Fields()->first()->getConfig();
|
||||
|
||||
$replacements = array(
|
||||
'GridFieldAddNewButton'=>'DMSGridFieldAddNewButton',
|
||||
'GridFieldEditButton'=>'DMSGridFieldEditButton'
|
||||
);
|
||||
|
||||
foreach ($replacements as $oldClass => $newClass) {
|
||||
// Our button is an instance of the original, so is returned when asking for the original
|
||||
$newButtons = $gridFieldConfig->getComponentsByType($oldClass);
|
||||
foreach ($newButtons as $key => $newButton) {
|
||||
if ($newButton instanceof $newClass) {
|
||||
// Remove our version for testing's sake
|
||||
$newButtons->remove($newButton);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertCount(0, $newButtons, 'Original button is removed');
|
||||
$this->assertInstanceOf(
|
||||
$newClass,
|
||||
$gridFieldConfig->getComponentByType($newClass),
|
||||
"Model admin for documents contains customised {$newClass} button"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Quick check to ensure that the ModelAdmin endpoint is working
|
||||
*/
|
||||
public function testModelAdminEndpointWorks()
|
||||
{
|
||||
$this->assertEquals(200, $this->get('admin/documents')->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the document sets GridField has a data column for the parent page title. Here we check for the
|
||||
* Page title existing in the DOM, since "Page" is guaranteed to exist somewhere else.
|
||||
*/
|
||||
public function testDocumentSetsGridFieldHasParentPageColumn()
|
||||
{
|
||||
$result = (string) $this->get('admin/documents/DMSDocumentSet')->getBody();
|
||||
$this->assertContains('Home Test Page', $result);
|
||||
$this->assertContains('About Us Test Page', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the document sets GridField has a data column which links to the DocumentSets tab on
|
||||
* the actual page in the CMS
|
||||
*/
|
||||
public function testDocumentSetsGridFieldHasLinkToCMSPageEditor()
|
||||
{
|
||||
$result = (string)$this->get('admin/documents/DMSDocumentSet')->getBody();
|
||||
$this->assertContains(
|
||||
"<a class='dms-doc-sets-link'",
|
||||
$result
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
Page:
|
||||
home:
|
||||
Title: Home Test Page
|
||||
URLSegment: home
|
||||
about_us:
|
||||
Title: About Us Test Page
|
||||
URLSegment: About Us
|
||||
|
||||
DMSDocumentSet:
|
||||
home_default:
|
||||
Title: Home Default
|
||||
Page: =>Page.home
|
||||
home_alt:
|
||||
Title: Home Alternative
|
||||
Page: =>Page.home
|
||||
about_default:
|
||||
Title: About Default
|
||||
Page: =>Page.about_us
|
||||
|
||||
DMSDocument:
|
||||
h_d_1:
|
||||
Title: Home Default 1
|
||||
Filename: home-default-1
|
||||
Sets: =>DMSDocumentSet.home_default
|
||||
h_a_2:
|
||||
Title: Home Default 2
|
||||
Filename: home-default-2
|
||||
Sets: =>DMSDocumentSet.home_alt
|
||||
a_d_1:
|
||||
Title: About Default 1
|
||||
Filename: about-default-1
|
||||
Sets: =>DMSDocumentSet.about_default
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
class DMSGridFieldAddNewButtonTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'dms/tests/dmstest.yml';
|
||||
|
||||
/**
|
||||
* @var DMSGridFieldAddNewButton
|
||||
*/
|
||||
protected $button;
|
||||
|
||||
/**
|
||||
* @var GridField
|
||||
*/
|
||||
protected $gridField;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$fakeList = DMSDocument::get();
|
||||
$this->gridField = GridField::create('TestGridField', false, $fakeList);
|
||||
$this->button = new DMSGridFieldAddNewButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when no document set ID is present then it is not added to the URL for "add document"
|
||||
*/
|
||||
public function testNoDocumentSetIdInAddUrlWhenNotProvided()
|
||||
{
|
||||
$this->assertNotContains('?dsid', $this->getButtonHtml());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when a document set ID is provided, it is added onto the "add document" link
|
||||
*/
|
||||
public function testDocumentSetIdAddedToLinkWhenProvided()
|
||||
{
|
||||
$this->button->setDocumentSetId(123);
|
||||
$this->assertContains('?dsid=123', $this->getButtonHtml());
|
||||
}
|
||||
|
||||
/**
|
||||
* If a set is saved and associated to a page, that page's ID should be added to the "add document" link to help
|
||||
* to ensure the user gets redirected back to the correct place afterwards
|
||||
*/
|
||||
public function testPageIdIsAddedWhenAvailableViaDocumentSetRelationship()
|
||||
{
|
||||
$set = $this->objFromFixture('DMSDocumentSet', 'ds1');
|
||||
$this->button->setDocumentSetId($set->ID);
|
||||
|
||||
$controller = new ContentController;
|
||||
$controller->pushCurrent();
|
||||
|
||||
$result = $this->getButtonHtml();
|
||||
$this->assertContains('dsid=' . $set->ID, $result, 'Add new button contains document set ID');
|
||||
$this->assertNotContains('page_id=' . $set->Page()->ID, $result, 'No page ID when not editing in page context');
|
||||
|
||||
$controller = new CMSPageEditController;
|
||||
$controller->pushCurrent();
|
||||
|
||||
$this->assertContains(
|
||||
'page_id=' . $set->Page()->ID,
|
||||
$this->getButtonHtml(),
|
||||
'Button contains page ID when in edit page context'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML result of the "add new" button, used for DRY in test class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getButtonHtml()
|
||||
{
|
||||
$fragments = $this->button->getHTMLFragments($this->gridField);
|
||||
return array_pop($fragments)->getValue();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
class DMSUploadFieldTest extends SapphireTest
|
||||
{
|
||||
/**
|
||||
* @var DMSUploadField
|
||||
*/
|
||||
protected $field;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->field = new DMSUploadField('StubUploadField');
|
||||
}
|
||||
|
||||
/**
|
||||
* SS 3.x injector will return an overloaded parent of a child class if the child is not injected.
|
||||
* This is a sanity check.
|
||||
*/
|
||||
public function testDmsUploadFieldIsInjectable()
|
||||
{
|
||||
$this->assertInstanceOf('DMSUploadField', DMSUploadField::create('Stub'));
|
||||
}
|
||||
|
||||
/**
|
||||
* The validator is coded to always return true. Replace this test if this behaviour changes in future.
|
||||
*/
|
||||
public function testValidatorAlwaysReturnsTrue()
|
||||
{
|
||||
$this->assertTrue($this->field->validate('foo'));
|
||||
}
|
||||
|
||||
public function testGetItemHandler()
|
||||
{
|
||||
$this->assertInstanceOf('DMSUploadField_ItemHandler', $this->field->getItemHandler(123));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the folder name can be get/set and that the value set is casted to a string
|
||||
*/
|
||||
public function testCanGetAndSetFolderName()
|
||||
{
|
||||
$this->field->setFolderName('qwerty');
|
||||
$this->assertSame('qwerty', $this->field->getFolderName());
|
||||
$this->field->setFolderName(123);
|
||||
$this->assertSame('123', $this->field->getFolderName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
class DMSUploadField_ItemHandlerTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'dms/tests/dmstest.yml';
|
||||
|
||||
/**
|
||||
* @var DMSDocument
|
||||
*/
|
||||
protected $document;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->document = $this->objFromFixture('DMSDocument', 'd1');
|
||||
}
|
||||
|
||||
public function testGetItem()
|
||||
{
|
||||
$handler = new DMSUploadField_ItemHandler(DMSUploadField::create('Test'), $this->document->ID);
|
||||
$result = $handler->getItem();
|
||||
$this->assertSame($result->ID, $this->document->ID, 'getItem returns the correct document from the database');
|
||||
}
|
||||
|
||||
public function testEditForm()
|
||||
{
|
||||
$handler = new DMSUploadField_ItemHandler(DMSUploadField::create('Test'), $this->document->ID);
|
||||
$result = $handler->EditForm();
|
||||
|
||||
$this->assertInstanceOf('Form', $result);
|
||||
$this->assertInstanceOf('DMSDocument', $result->getRecord());
|
||||
$this->assertSame($this->document->ID, $result->getRecord()->ID);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
DMSDocumentSet:
|
||||
ds1:
|
||||
Title: Document Set 1
|
||||
SiteTree:
|
||||
s1:
|
||||
Title: testPage1
|
||||
URLSegment: s1
|
||||
DocumentSets: =>DMSDocumentSet.ds1
|
||||
s2:
|
||||
Title: testPage2
|
||||
URLSegment: s2
|
||||
|
|
|
@ -1,49 +1,134 @@
|
|||
SiteTree:
|
||||
s1:
|
||||
Title: testPage1
|
||||
Title: testPage1 has document sets
|
||||
URLSegment: s1
|
||||
s2:
|
||||
Title: testPage2
|
||||
Title: testPage2 a document set
|
||||
URLSegment: s2
|
||||
s3:
|
||||
Title: testPage3
|
||||
Title: testPage3 has document sets with embargoed docs
|
||||
URLSegment: s3
|
||||
s4:
|
||||
Title: testPage4
|
||||
Title: testPage4 has no sets
|
||||
URLSegment: s4
|
||||
s5:
|
||||
Title: testPage5
|
||||
Title: testPage5 has no sets
|
||||
URLSegment: s5
|
||||
s6:
|
||||
Title: testPage6
|
||||
Title: testPage6 has no sets
|
||||
URLSegment: s6
|
||||
DMSTag:
|
||||
t1:
|
||||
Category: tag1
|
||||
Value: tag1value
|
||||
t2:
|
||||
Category: tag2
|
||||
Value: tag2value
|
||||
t3:
|
||||
Category: tag3
|
||||
Value: tag3value
|
||||
t4:
|
||||
Category: tag4
|
||||
Value: tag4value
|
||||
t5:
|
||||
Category: tag5
|
||||
Value: tag5value
|
||||
t6:
|
||||
Category: tag6
|
||||
Value: tag6value
|
||||
s7:
|
||||
Title: testPage7 has documents embargoed until publish
|
||||
URLSegment: s7
|
||||
s8:
|
||||
Title: testPage8
|
||||
URLSegment: s8
|
||||
s9:
|
||||
Title: testPage9
|
||||
URLSegment: s9
|
||||
Group:
|
||||
content-author:
|
||||
Code: content-author
|
||||
Title: "Content Author"
|
||||
cable-guy:
|
||||
Code: cable-guy
|
||||
Title: "Cable Guy"
|
||||
Member:
|
||||
editor:
|
||||
Name: editor
|
||||
Groups: =>Group.content-author
|
||||
non-editor:
|
||||
Name: cable-guy
|
||||
Groups: =>Group.cable-guy
|
||||
DMSDocumentSet:
|
||||
ds1:
|
||||
Title: Document Set 1
|
||||
Page: =>SiteTree.s1
|
||||
ds2:
|
||||
Title: Document Set 2
|
||||
Page: =>SiteTree.s1
|
||||
ds3:
|
||||
Title: Document Set 3
|
||||
Page: =>SiteTree.s2
|
||||
ds4:
|
||||
Title: Set containing embargoed documents
|
||||
Page: =>SiteTree.s3
|
||||
ds5:
|
||||
Title: Set containing embargoed until publish documents
|
||||
Page: =>SiteTree.s7
|
||||
ds6:
|
||||
Title: Test Set 6
|
||||
Page: =>SiteTree.s8
|
||||
dsSaveLinkedDocuments:
|
||||
Title: Test Set 6
|
||||
Page: =>SiteTree.s9
|
||||
unlinked_set:
|
||||
Title: Document Set not linked
|
||||
DMSDocument:
|
||||
d1:
|
||||
Filename: test-file-file-doesnt-exist
|
||||
Filename: test-file-file-doesnt-exist-1
|
||||
Folder: 5
|
||||
Tags: =>DMSTag.t1, =>DMSTag.t2, =>DMSTag.t3, =>DMSTag.t4
|
||||
Pages: =>SiteTree.s1, =>SiteTree.s2, =>SiteTree.s3, =>SiteTree.s4, =>SiteTree.s5, =>SiteTree.s6
|
||||
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
|
||||
d2:
|
||||
Filename: test-file-file-doesnt-exist
|
||||
Filename: test-file-file-doesnt-exist-2
|
||||
Folder: 5
|
||||
Tags: =>DMSTag.t5, =>DMSTag.t6
|
||||
Pages: =>SiteTree.s5, =>SiteTree.s6
|
||||
Title: File That Doesn't Exist (Title)
|
||||
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
|
||||
document_with_relations:
|
||||
Filename: file-with-relations
|
||||
Folder: 5
|
||||
RelatedDocuments: =>DMSDocument.d1, =>DMSDocument.d2
|
||||
doc-logged-in-users:
|
||||
FileName: doc-logged-in-users
|
||||
CanViewType: LoggedInUsers
|
||||
CanEditType: LoggedInUsers
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
|
||||
doc-anyone:
|
||||
FileName: doc-anyone
|
||||
CanViewType: Anyone
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
|
||||
doc-only-these-users:
|
||||
FileName: doc-only-these-users
|
||||
CanViewType: OnlyTheseUsers
|
||||
CanEditType: OnlyTheseUsers
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.ds1, =>DMSDocumentSet.ds2, =>DMSDocumentSet.ds3, =>DMSDocumentSet.ds4
|
||||
ViewerGroups: =>Group.content-author
|
||||
EditorGroups: =>Group.content-author
|
||||
embargoed_document1:
|
||||
Filename: foobar
|
||||
EmbargoedIndefinitely: true
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.ds4
|
||||
embargo_until_publish1:
|
||||
Filename: embargo-until-publish1
|
||||
EmbargoUntilPublish: true
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.ds5
|
||||
embargo_until_publish2:
|
||||
Filename: embargo-until-publish2
|
||||
EmbargoUntilPublish: true
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.ds5
|
||||
extraDoc1:
|
||||
Filename: extradoc1
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.ds6
|
||||
ManuallyAdded: 1
|
||||
CreatedByID: 2
|
||||
extraDoc2:
|
||||
Filename: extradoc2
|
||||
Folder: 5
|
||||
CreatedByID: 2
|
||||
ManuallyAdded: 0
|
||||
extraDoc3:
|
||||
Filename: extradoc3
|
||||
Folder: 5
|
||||
ManuallyAdded: 0
|
||||
CreatedByID: 2
|
||||
docSaveLinkedDocuments1:
|
||||
Filename: saveLinkedDocument1
|
||||
Folder: 5
|
||||
Sets: =>DMSDocumentSet.dsSaveLinkedDocuments
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
class DMSDocumentTaxonomyExtensionTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'DMSDocumentTaxonomyExtensionTest.yml';
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!class_exists('TaxonomyType')) {
|
||||
$this->markTestSkipped('This test requires silverstripe/taxonomy ^1.2 to be installed. Skipping.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that appropriate tags by taxonomy type are returned, and that their hierarchy is displayd in the title
|
||||
*/
|
||||
public function testGetAllTagsMap()
|
||||
{
|
||||
$extension = new DMSDocumentTaxonomyExtension;
|
||||
$result = $extension->getAllTagsMap();
|
||||
|
||||
$this->assertContains('Subject > Mathematics', $result);
|
||||
$this->assertContains('Subject', $result);
|
||||
$this->assertContains('Subject > Science > Chemistry', $result);
|
||||
$this->assertNotContains('Physical Education', $result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
TaxonomyType:
|
||||
document:
|
||||
Name: Document
|
||||
not_a_document:
|
||||
Name: Not A Document
|
||||
|
||||
TaxonomyTerm:
|
||||
subject:
|
||||
Name: Subject
|
||||
Type: =>TaxonomyType.document
|
||||
maths:
|
||||
Name: Mathematics
|
||||
Parent: =>TaxonomyTerm.subject
|
||||
Type: =>TaxonomyType.document
|
||||
science:
|
||||
Name: Science
|
||||
Parent: =>TaxonomyTerm.subject
|
||||
Type: =>TaxonomyType.document
|
||||
chemistry:
|
||||
Name: Chemistry
|
||||
Parent: =>TaxonomyTerm.science
|
||||
Type: =>TaxonomyType.document
|
||||
chemistry_level_1:
|
||||
Name: Level 1
|
||||
Parent: =>TaxonomyTerm.chemistry
|
||||
Type: =>TaxonomyType.document
|
||||
# Not applicable to DMS documents, but here for testing edge cases
|
||||
physed:
|
||||
Name: Physical Education
|
||||
Type: =>TaxonomyType.not_a_document
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
class DMSSiteTreeExtensionTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'dms/tests/dmstest.yml';
|
||||
|
||||
protected $requiredExtensions = array(
|
||||
'SiteTree' => array('DMSSiteTreeExtension')
|
||||
);
|
||||
|
||||
/**
|
||||
* Ensure that setting the configuration property "documents_enabled" to false for a page type will prevent the
|
||||
* CMS fields from being modified.
|
||||
*
|
||||
* Also ensures that a correctly named Document Sets GridField is added to the fields in the right place.
|
||||
*
|
||||
* Note: the (1) is the number of sets defined for this SiteTree in the fixture
|
||||
*
|
||||
* @dataProvider documentSetEnabledConfigProvider
|
||||
*/
|
||||
public function testCanDisableDocumentSetsTab($configSetting, $assertionMethod)
|
||||
{
|
||||
Config::inst()->update('SiteTree', 'documents_enabled', $configSetting);
|
||||
$siteTree = $this->objFromFixture('SiteTree', 's2');
|
||||
$this->$assertionMethod($siteTree->getCMSFields()->fieldByName('Root.DocumentSets.DocumentSets'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
public function documentSetEnabledConfigProvider()
|
||||
{
|
||||
return array(
|
||||
array(true, 'assertNotNull'),
|
||||
array(false, 'assertNull')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for the Document Sets GridField.
|
||||
*
|
||||
* Note: the (1) is the number of sets defined for this SiteTree in the fixture
|
||||
*/
|
||||
public function testDocumentSetsGridFieldIsCorrectlyConfigured()
|
||||
{
|
||||
Config::inst()->update('SiteTree', 'documents_enabled', true);
|
||||
$siteTree = $this->objFromFixture('SiteTree', 's2');
|
||||
$gridField = $siteTree->getCMSFields()->fieldByName('Root.DocumentSets.DocumentSets');
|
||||
|
||||
$this->assertInstanceOf('GridField', $gridField);
|
||||
$this->assertTrue((bool) $gridField->hasClass('documentsets'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a page title can be retrieved with the number of related documents it has (across all document sets).
|
||||
*
|
||||
* See fixtures for relationships that define this result.
|
||||
*/
|
||||
public function testGetTitleWithNumberOfDocuments()
|
||||
{
|
||||
$siteTree = $this->objFromFixture('SiteTree', 's1');
|
||||
$this->assertSame('testPage1 has document sets (5)', $siteTree->getTitleWithNumberOfDocuments());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that documents marked as "embargo until publish" are unmarked as such when a page containing them is
|
||||
* published
|
||||
*/
|
||||
public function testOnBeforePublishUnEmbargoesDocumentsSetAsEmbargoedUntilPublish()
|
||||
{
|
||||
$siteTree = $this->objFromFixture('SiteTree', 's7');
|
||||
$siteTree->doPublish();
|
||||
|
||||
// Fixture defines this page as having two documents via one set
|
||||
foreach (array('embargo-until-publish1', 'embargo-until-publish2') as $filename) {
|
||||
$this->assertFalse(
|
||||
(bool) $siteTree->getAllDocuments()
|
||||
->filter('Filename', 'embargo-until-publish1')
|
||||
->first()
|
||||
->EmbargoedUntilPublished
|
||||
);
|
||||
}
|
||||
$this->assertCount(0, $siteTree->getAllDocuments()->filter('EmbargoedUntilPublished', true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that document sets that are assigned to pages to not show up in "link existing" autocomplete
|
||||
* search results
|
||||
*/
|
||||
public function testGetRelatedDocumentsForAutocompleter()
|
||||
{
|
||||
$page = $this->objFromFixture('SiteTree', 's1');
|
||||
$gridField = $page->getCMSFields()->fieldByName('Root.DocumentSets.DocumentSets');
|
||||
$this->assertInstanceOf('GridField', $gridField);
|
||||
|
||||
$autocompleter = $gridField->getConfig()->getComponentByType('GridFieldAddExistingAutocompleter');
|
||||
$jsonResult = $autocompleter->doSearch(
|
||||
$gridField,
|
||||
new SS_HTTPRequest('GET', '/', array('gridfield_relationsearch' => 'Document Set'))
|
||||
);
|
||||
|
||||
$this->assertContains('Document Set not linked', $jsonResult);
|
||||
$this->assertNotContains('Document Set 1', $jsonResult);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
class DMSTaxonomyTypeExtensionTest extends SapphireTest
|
||||
{
|
||||
protected $usesDatabase = true;
|
||||
|
||||
protected $requiredExtensions = array(
|
||||
'TaxonomyType' => array('DMSTaxonomyTypeExtension')
|
||||
);
|
||||
|
||||
/**
|
||||
* Ensure that the configurable list of default records are created
|
||||
*/
|
||||
public function testDefaultRecordsAreCreated()
|
||||
{
|
||||
Config::inst()->update('DMSTaxonomyTypeExtension', 'default_records', array('Food', 'Beverage', 'Books'));
|
||||
|
||||
TaxonomyType::create()->requireDefaultRecords();
|
||||
|
||||
$this->assertDOSContains(
|
||||
array(
|
||||
array('Name' => 'Food'),
|
||||
array('Name' => 'Beverage'),
|
||||
array('Name' => 'Books'),
|
||||
),
|
||||
TaxonomyType::get()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
class DMSJsonFieldTest extends SapphireTest
|
||||
{
|
||||
public function testJsonFieldConstructorMultiWays()
|
||||
{
|
||||
$jsonField = new DMSJsonField('MyJsonField', new FieldList(
|
||||
new TextField('FirstName', 'Given name'),
|
||||
new TextField('Surname', 'Last name')
|
||||
));
|
||||
$this->assertEquals($jsonField->FieldList()->count(), 2);
|
||||
$this->assertNotNull($jsonField->FieldList()->dataFieldByName('MyJsonField[FirstName]'));
|
||||
|
||||
$jsonField = new DMSJsonField('MyJsonField', array(new TextField('FirstName', 'Given name'),
|
||||
new TextField('Surname', 'Last name')));
|
||||
$this->assertEquals($jsonField->FieldList()->count(), 2);
|
||||
$this->assertNotNull($jsonField->FieldList()->dataFieldByName('MyJsonField[FirstName]'));
|
||||
|
||||
$jsonField = new DMSJsonField(
|
||||
'MyJsonField',
|
||||
new TextField('FirstName', 'Given name'),
|
||||
new TextField('Surname', 'Last name')
|
||||
);
|
||||
$this->assertEquals($jsonField->FieldList()->count(), 2);
|
||||
$this->assertNotNull($jsonField->FieldList()->dataFieldByName('MyJsonField[FirstName]'));
|
||||
}
|
||||
|
||||
public function testJsonFieldDataValueCouldDealWithArray()
|
||||
{
|
||||
$jsonField = new DMSJsonField('MyJsonField', new FieldList(
|
||||
new TextField('FirstName', 'Given name'),
|
||||
new TextField('Surname', 'Last name')
|
||||
));
|
||||
$jsonField->setValue($value = array(
|
||||
'MyJsonField'=>array(
|
||||
'FirstName' => 'Normann',
|
||||
'Surname' => 'Lou',
|
||||
),
|
||||
));
|
||||
|
||||
$this->assertEquals($jsonField->dataValue(), Convert::array2json($value));
|
||||
$jsonField->setValue($value = array(
|
||||
'MyJsonField'=>array(),
|
||||
));
|
||||
$this->assertNull($jsonField->dataValue());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
class MigrateToDocumentSetsTaskTest extends SapphireTest
|
||||
{
|
||||
protected static $fixture_file = 'MigrateToDocumentSetsTaskTest.yml';
|
||||
|
||||
/**
|
||||
* Ensure that output is formatted either for the CLI or browser
|
||||
*
|
||||
* @param bool $isCli
|
||||
* @param string $expected
|
||||
* @dataProvider outputProvider
|
||||
*/
|
||||
public function testCanOutputToCliOrBrowser($isCli, $expected)
|
||||
{
|
||||
$lines = array('Test', 'Test line 2');
|
||||
|
||||
$mock = $this->getMockBuilder('MigrateToDocumentSetsTask')
|
||||
->setMethods(array('isCli'))
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->exactly(2))
|
||||
->method('isCli')
|
||||
->will($this->returnValue($isCli));
|
||||
|
||||
ob_start();
|
||||
foreach ($lines as $line) {
|
||||
$mock->output($line);
|
||||
}
|
||||
$result = ob_get_clean();
|
||||
$this->assertSame($expected, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
public function outputProvider()
|
||||
{
|
||||
return array(
|
||||
array(true, 'Test' . PHP_EOL . 'Test line 2' . PHP_EOL),
|
||||
array(false, 'Test<br />Test line 2<br />')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that providing an invalid action returns an error
|
||||
*/
|
||||
public function testShowErrorOnInvalidAction()
|
||||
{
|
||||
$result = $this->runTask(array('action' => 'coffeetime'));
|
||||
$this->assertContains('Error! Specified action is not valid.', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that default document sets can be created for those pages that don't have them already
|
||||
*/
|
||||
public function testCreateDefaultDocumentSets()
|
||||
{
|
||||
$this->fixtureOldRelations();
|
||||
|
||||
$result = $this->runTask(array('action' => 'create-default-document-set'));
|
||||
$this->assertContains('Finished', $result);
|
||||
// There are four pages in the fixture, but one of them already has a document set, so should be unchanged
|
||||
$this->assertContains('Default document set added: 3', $result);
|
||||
$this->assertContains('Skipped: already has a set: 1', $result);
|
||||
|
||||
// Test that some of the relationship records were written correctly
|
||||
$this->assertCount(1, $firstPageSets = $this->objFromFixture('SiteTree', 'one')->getDocumentSets());
|
||||
$this->assertSame('Default', $firstPageSets->first()->Title);
|
||||
$this->assertCount(1, $this->objFromFixture('SiteTree', 'two')->getDocumentSets());
|
||||
|
||||
// With dryrun enabled and being run the second time, nothing should be done
|
||||
$result = $this->runTask(array('action' => 'create-default-document-set', 'dryrun' => '1'));
|
||||
$this->assertContains('Skipped: already has a set: 4', $result);
|
||||
$this->assertContains('NOTE: Dryrun mode enabled', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that legacy ORM relationship maps are migrated to the new page -> document set -> document relationship
|
||||
*/
|
||||
public function testReassignDocumentsToFirstSet()
|
||||
{
|
||||
$this->fixtureOldRelations();
|
||||
|
||||
// Ensure default sets are created
|
||||
$this->runTask(array('action' => 'create-default-document-set'));
|
||||
|
||||
// Dryrun check
|
||||
$result = $this->runTask(array('action' => 'reassign-documents', 'dryrun' => '1'));
|
||||
$this->assertContains('NOTE: Dryrun mode enabled', $result);
|
||||
$this->assertContains('Reassigned to document set: 3', $result);
|
||||
|
||||
// Actual run
|
||||
$result = $this->runTask(array('action' => 'reassign-documents'));
|
||||
$this->assertNotContains('NOTE: Dryrun mode enabled', $result);
|
||||
$this->assertContains('Reassigned to document set: 3', $result);
|
||||
|
||||
// Smoke ORM checks
|
||||
$this->assertCount(1, $this->objFromFixture('SiteTree', 'one')->getAllDocuments());
|
||||
$this->assertCount(1, $this->objFromFixture('SiteTree', 'two')->getAllDocuments());
|
||||
$this->assertCount(0, $this->objFromFixture('SiteTree', 'four')->getAllDocuments());
|
||||
}
|
||||
|
||||
/**
|
||||
* Centralises (slightly) logic for capturing direct output from the task
|
||||
*
|
||||
* @param array $getVars
|
||||
* @return string Task output
|
||||
*/
|
||||
protected function runTask(array $getVars)
|
||||
{
|
||||
$task = new MigrateToDocumentSetsTask;
|
||||
$request = new SS_HTTPRequest('GET', '/', $getVars);
|
||||
|
||||
ob_start();
|
||||
$task->run($request);
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the old many many relationship table from documents to pages
|
||||
*/
|
||||
protected function fixtureOldRelations()
|
||||
{
|
||||
if (!DB::get_schema()->hasTable('DMSDocument_Pages')) {
|
||||
DB::create_table('DMSDocument_Pages', array(
|
||||
'DMSDocumentID' => 'int(11) null',
|
||||
'SiteTreeID' => 'int(11) null'
|
||||
));
|
||||
}
|
||||
|
||||
$documentIds = $this->getFixtureFactory()->getIds('DMSDocument');
|
||||
$pageIds = $this->getFixtureFactory()->getIds('SiteTree');
|
||||
foreach (array('one', 'two', 'three') as $fixtureName) {
|
||||
$this->getFixtureFactory()->createRaw(
|
||||
'DMSDocument_Pages',
|
||||
'rln_' . $fixtureName,
|
||||
array('DMSDocumentID' => $documentIds[$fixtureName], 'SiteTreeID' => $pageIds[$fixtureName])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
# Fixtures for migration task testing. The relationships for them are
|
||||
# created manually in the unit test class.
|
||||
DMSDocument:
|
||||
one:
|
||||
Title: document1
|
||||
two:
|
||||
Title: document2
|
||||
three:
|
||||
Title: document3
|
||||
DMSDocumentSet:
|
||||
four:
|
||||
Title: documentSet4
|
||||
SiteTree:
|
||||
one:
|
||||
Title: page1
|
||||
two:
|
||||
Title: page2
|
||||
three:
|
||||
Title: page3
|
||||
four:
|
||||
Title: page4
|
||||
DocumentSets: =>DMSDocumentSet.four
|
|
@ -0,0 +1,41 @@
|
|||
const ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||
const path = require('path');
|
||||
|
||||
const extractSass = new ExtractTextPlugin({
|
||||
filename: '[name].css',
|
||||
allChunks: true
|
||||
});
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
name: 'css',
|
||||
entry: {
|
||||
cmsbundle: './scss/main.scss',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist/css'),
|
||||
filename: '[name].css',
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.scss$/,
|
||||
use: extractSass.extract({
|
||||
use: [{
|
||||
loader: 'css-loader?discardComments'
|
||||
}, {
|
||||
loader: 'sass-loader'
|
||||
}],
|
||||
fallback: 'style-loader'
|
||||
})
|
||||
}, {
|
||||
test: /\.(jpg|gif|png|svg)$/,
|
||||
use: [{
|
||||
loader: 'file-loader?emitFile=false&name=../../[path][name].[ext]'
|
||||
}]
|
||||
}]
|
||||
},
|
||||
plugins: [
|
||||
extractSass
|
||||
]
|
||||
}
|
||||
];
|
|
@ -0,0 +1,3819 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
acorn-dynamic-import@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
|
||||
integrity sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=
|
||||
dependencies:
|
||||
acorn "^4.0.3"
|
||||
|
||||
acorn@^4.0.3:
|
||||
version "4.0.13"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
|
||||
integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=
|
||||
|
||||
acorn@^5.0.0:
|
||||
version "5.7.3"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
|
||||
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
|
||||
|
||||
ajv-keywords@^1.1.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
|
||||
integrity sha1-MU3QpLM2j609/NxU7eYXG4htrzw=
|
||||
|
||||
ajv@^4.7.0:
|
||||
version "4.11.8"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
|
||||
integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=
|
||||
dependencies:
|
||||
co "^4.6.0"
|
||||
json-stable-stringify "^1.0.1"
|
||||
|
||||
ajv@^5.0.0:
|
||||
version "5.5.2"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
|
||||
integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=
|
||||
dependencies:
|
||||
co "^4.6.0"
|
||||
fast-deep-equal "^1.0.0"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.3.0"
|
||||
|
||||
ajv@^6.5.5:
|
||||
version "6.10.2"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
|
||||
integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
|
||||
dependencies:
|
||||
fast-deep-equal "^2.0.1"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
align-text@^0.1.1, align-text@^0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
|
||||
integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=
|
||||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
longest "^1.0.1"
|
||||
repeat-string "^1.5.2"
|
||||
|
||||
alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
|
||||
integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
|
||||
|
||||
amdefine@>=0.0.4:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||
integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
|
||||
|
||||
ansi-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
ansi-styles@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
||||
integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
|
||||
dependencies:
|
||||
color-convert "^1.9.0"
|
||||
|
||||
anymatch@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
|
||||
integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==
|
||||
dependencies:
|
||||
micromatch "^3.1.4"
|
||||
normalize-path "^2.1.1"
|
||||
|
||||
aproba@^1.0.3:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
|
||||
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
|
||||
|
||||
are-we-there-yet@~1.1.2:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
|
||||
integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
|
||||
dependencies:
|
||||
delegates "^1.0.0"
|
||||
readable-stream "^2.0.6"
|
||||
|
||||
argparse@^1.0.7:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
|
||||
arr-diff@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
|
||||
integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
|
||||
|
||||
arr-flatten@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
|
||||
integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
|
||||
|
||||
arr-union@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
|
||||
integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
|
||||
|
||||
array-find-index@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
||||
integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
|
||||
|
||||
array-unique@^0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
|
||||
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
|
||||
|
||||
asn1.js@^4.0.0:
|
||||
version "4.10.1"
|
||||
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
|
||||
integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
|
||||
dependencies:
|
||||
bn.js "^4.0.0"
|
||||
inherits "^2.0.1"
|
||||
minimalistic-assert "^1.0.0"
|
||||
|
||||
asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
||||
dependencies:
|
||||
safer-buffer "~2.1.0"
|
||||
|
||||
assert-plus@1.0.0, assert-plus@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
|
||||
|
||||
assert@^1.1.1:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
|
||||
integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==
|
||||
dependencies:
|
||||
object-assign "^4.1.1"
|
||||
util "0.10.3"
|
||||
|
||||
assign-symbols@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
|
||||
integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
|
||||
|
||||
async-each@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
|
||||
integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
|
||||
|
||||
async-foreach@^0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
|
||||
integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
|
||||
|
||||
async@^2.1.2:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
|
||||
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
|
||||
dependencies:
|
||||
lodash "^4.17.14"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
|
||||
|
||||
atob@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||
|
||||
autoprefixer@^6.3.1:
|
||||
version "6.7.7"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
|
||||
integrity sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=
|
||||
dependencies:
|
||||
browserslist "^1.7.6"
|
||||
caniuse-db "^1.0.30000634"
|
||||
normalize-range "^0.1.2"
|
||||
num2fraction "^1.2.2"
|
||||
postcss "^5.2.16"
|
||||
postcss-value-parser "^3.2.3"
|
||||
|
||||
aws-sign2@~0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
|
||||
|
||||
aws4@^1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
||||
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
|
||||
|
||||
babel-code-frame@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
||||
integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
|
||||
dependencies:
|
||||
chalk "^1.1.3"
|
||||
esutils "^2.0.2"
|
||||
js-tokens "^3.0.2"
|
||||
|
||||
balanced-match@^0.4.2:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
|
||||
integrity sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
base64-js@^1.0.2:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
|
||||
integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
|
||||
|
||||
base@^0.11.1:
|
||||
version "0.11.2"
|
||||
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
|
||||
integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
|
||||
dependencies:
|
||||
cache-base "^1.0.1"
|
||||
class-utils "^0.3.5"
|
||||
component-emitter "^1.2.1"
|
||||
define-property "^1.0.0"
|
||||
isobject "^3.0.1"
|
||||
mixin-deep "^1.2.0"
|
||||
pascalcase "^0.1.1"
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
||||
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
|
||||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
big.js@^3.1.3:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
|
||||
integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==
|
||||
|
||||
big.js@^5.2.2:
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
||||
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
||||
|
||||
binary-extensions@^1.0.0:
|
||||
version "1.13.1"
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
|
||||
integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
|
||||
|
||||
block-stream@*:
|
||||
version "0.0.9"
|
||||
resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
|
||||
integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=
|
||||
dependencies:
|
||||
inherits "~2.0.0"
|
||||
|
||||
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
|
||||
version "4.11.9"
|
||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
|
||||
integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
braces@^2.3.1, braces@^2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
|
||||
integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
|
||||
dependencies:
|
||||
arr-flatten "^1.1.0"
|
||||
array-unique "^0.3.2"
|
||||
extend-shallow "^2.0.1"
|
||||
fill-range "^4.0.0"
|
||||
isobject "^3.0.1"
|
||||
repeat-element "^1.1.2"
|
||||
snapdragon "^0.8.1"
|
||||
snapdragon-node "^2.0.1"
|
||||
split-string "^3.0.2"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
brorand@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
|
||||
integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
|
||||
|
||||
browserify-aes@^1.0.0, browserify-aes@^1.0.4:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
|
||||
integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
|
||||
dependencies:
|
||||
buffer-xor "^1.0.3"
|
||||
cipher-base "^1.0.0"
|
||||
create-hash "^1.1.0"
|
||||
evp_bytestokey "^1.0.3"
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
browserify-cipher@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
|
||||
integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==
|
||||
dependencies:
|
||||
browserify-aes "^1.0.4"
|
||||
browserify-des "^1.0.0"
|
||||
evp_bytestokey "^1.0.0"
|
||||
|
||||
browserify-des@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
|
||||
integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==
|
||||
dependencies:
|
||||
cipher-base "^1.0.1"
|
||||
des.js "^1.0.0"
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.1.2"
|
||||
|
||||
browserify-rsa@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
|
||||
integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=
|
||||
dependencies:
|
||||
bn.js "^4.1.0"
|
||||
randombytes "^2.0.1"
|
||||
|
||||
browserify-sign@^4.0.0:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
|
||||
integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=
|
||||
dependencies:
|
||||
bn.js "^4.1.1"
|
||||
browserify-rsa "^4.0.0"
|
||||
create-hash "^1.1.0"
|
||||
create-hmac "^1.1.2"
|
||||
elliptic "^6.0.0"
|
||||
inherits "^2.0.1"
|
||||
parse-asn1 "^5.0.0"
|
||||
|
||||
browserify-zlib@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
|
||||
integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==
|
||||
dependencies:
|
||||
pako "~1.0.5"
|
||||
|
||||
browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
|
||||
version "1.7.7"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
|
||||
integrity sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=
|
||||
dependencies:
|
||||
caniuse-db "^1.0.30000639"
|
||||
electron-to-chromium "^1.2.7"
|
||||
|
||||
buffer-xor@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
|
||||
integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
|
||||
|
||||
buffer@^4.3.0:
|
||||
version "4.9.2"
|
||||
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
|
||||
integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
|
||||
dependencies:
|
||||
base64-js "^1.0.2"
|
||||
ieee754 "^1.1.4"
|
||||
isarray "^1.0.0"
|
||||
|
||||
builtin-status-codes@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
||||
|
||||
cache-base@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
|
||||
integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
|
||||
dependencies:
|
||||
collection-visit "^1.0.0"
|
||||
component-emitter "^1.2.1"
|
||||
get-value "^2.0.6"
|
||||
has-value "^1.0.0"
|
||||
isobject "^3.0.1"
|
||||
set-value "^2.0.0"
|
||||
to-object-path "^0.3.0"
|
||||
union-value "^1.0.0"
|
||||
unset-value "^1.0.0"
|
||||
|
||||
camelcase-keys@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
|
||||
integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
|
||||
dependencies:
|
||||
camelcase "^2.0.0"
|
||||
map-obj "^1.0.0"
|
||||
|
||||
camelcase@^1.0.2:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
|
||||
integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=
|
||||
|
||||
camelcase@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
|
||||
integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
|
||||
|
||||
camelcase@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
|
||||
integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
|
||||
|
||||
caniuse-api@^1.5.2:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
|
||||
integrity sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=
|
||||
dependencies:
|
||||
browserslist "^1.3.6"
|
||||
caniuse-db "^1.0.30000529"
|
||||
lodash.memoize "^4.1.2"
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
|
||||
version "1.0.30001008"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001008.tgz#1691f28db0e08bf6abb5e472d8aaea392ec4a995"
|
||||
integrity sha512-Fog+uREPKb/RDc0puoAqqBZB05I8wYff+TIMDkYw9Lweq7+hUEN5fNLpIaBX6AJxq4sndqPct8fYLrDUV6u4xw==
|
||||
|
||||
caseless@~0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
|
||||
|
||||
center-align@^0.1.1:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
|
||||
integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60=
|
||||
dependencies:
|
||||
align-text "^0.1.3"
|
||||
lazy-cache "^1.0.3"
|
||||
|
||||
chalk@^1.1.1, chalk@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
|
||||
integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
|
||||
dependencies:
|
||||
ansi-styles "^2.2.1"
|
||||
escape-string-regexp "^1.0.2"
|
||||
has-ansi "^2.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
supports-color "^2.0.0"
|
||||
|
||||
chalk@^2.4.1:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
dependencies:
|
||||
ansi-styles "^3.2.1"
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chokidar@^2.0.2:
|
||||
version "2.1.8"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
|
||||
integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
|
||||
dependencies:
|
||||
anymatch "^2.0.0"
|
||||
async-each "^1.0.1"
|
||||
braces "^2.3.2"
|
||||
glob-parent "^3.1.0"
|
||||
inherits "^2.0.3"
|
||||
is-binary-path "^1.0.0"
|
||||
is-glob "^4.0.0"
|
||||
normalize-path "^3.0.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
readdirp "^2.2.1"
|
||||
upath "^1.1.1"
|
||||
optionalDependencies:
|
||||
fsevents "^1.2.7"
|
||||
|
||||
chownr@^1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142"
|
||||
integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==
|
||||
|
||||
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
|
||||
integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
|
||||
dependencies:
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
clap@^1.0.9:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51"
|
||||
integrity sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==
|
||||
dependencies:
|
||||
chalk "^1.1.3"
|
||||
|
||||
class-utils@^0.3.5:
|
||||
version "0.3.6"
|
||||
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
||||
integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
|
||||
dependencies:
|
||||
arr-union "^3.1.0"
|
||||
define-property "^0.2.5"
|
||||
isobject "^3.0.0"
|
||||
static-extend "^0.1.1"
|
||||
|
||||
cliui@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
|
||||
integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=
|
||||
dependencies:
|
||||
center-align "^0.1.1"
|
||||
right-align "^0.1.1"
|
||||
wordwrap "0.0.2"
|
||||
|
||||
cliui@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
|
||||
integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
|
||||
dependencies:
|
||||
string-width "^1.0.1"
|
||||
strip-ansi "^3.0.1"
|
||||
wrap-ansi "^2.0.0"
|
||||
|
||||
clone-deep@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713"
|
||||
integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==
|
||||
dependencies:
|
||||
for-own "^1.0.0"
|
||||
is-plain-object "^2.0.4"
|
||||
kind-of "^6.0.0"
|
||||
shallow-clone "^1.0.0"
|
||||
|
||||
clone@^1.0.2:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
|
||||
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
|
||||
|
||||
co@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||
integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
|
||||
|
||||
coa@~1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd"
|
||||
integrity sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=
|
||||
dependencies:
|
||||
q "^1.1.2"
|
||||
|
||||
code-point-at@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
||||
|
||||
collection-visit@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
|
||||
integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
|
||||
dependencies:
|
||||
map-visit "^1.0.0"
|
||||
object-visit "^1.0.0"
|
||||
|
||||
color-convert@^1.3.0, color-convert@^1.9.0:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
|
||||
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
|
||||
dependencies:
|
||||
color-name "1.1.3"
|
||||
|
||||
color-name@1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
|
||||
|
||||
color-name@^1.0.0:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-string@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991"
|
||||
integrity sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=
|
||||
dependencies:
|
||||
color-name "^1.0.0"
|
||||
|
||||
color@^0.11.0:
|
||||
version "0.11.4"
|
||||
resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
|
||||
integrity sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=
|
||||
dependencies:
|
||||
clone "^1.0.2"
|
||||
color-convert "^1.3.0"
|
||||
color-string "^0.3.0"
|
||||
|
||||
colormin@^1.0.5:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133"
|
||||
integrity sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=
|
||||
dependencies:
|
||||
color "^0.11.0"
|
||||
css-color-names "0.0.4"
|
||||
has "^1.0.1"
|
||||
|
||||
colors@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
|
||||
integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM=
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
component-emitter@^1.2.1:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
|
||||
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
console-browserify@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336"
|
||||
integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==
|
||||
|
||||
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
||||
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
|
||||
|
||||
constants-browserify@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
||||
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
|
||||
|
||||
copy-descriptor@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
|
||||
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
|
||||
|
||||
core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
|
||||
|
||||
create-ecdh@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
|
||||
integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==
|
||||
dependencies:
|
||||
bn.js "^4.1.0"
|
||||
elliptic "^6.0.0"
|
||||
|
||||
create-hash@^1.1.0, create-hash@^1.1.2:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
|
||||
integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
|
||||
dependencies:
|
||||
cipher-base "^1.0.1"
|
||||
inherits "^2.0.1"
|
||||
md5.js "^1.3.4"
|
||||
ripemd160 "^2.0.1"
|
||||
sha.js "^2.4.0"
|
||||
|
||||
create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
|
||||
integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
|
||||
dependencies:
|
||||
cipher-base "^1.0.3"
|
||||
create-hash "^1.1.0"
|
||||
inherits "^2.0.1"
|
||||
ripemd160 "^2.0.0"
|
||||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
cross-spawn@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
|
||||
integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI=
|
||||
dependencies:
|
||||
lru-cache "^4.0.1"
|
||||
which "^1.2.9"
|
||||
|
||||
crypto-browserify@^3.11.0:
|
||||
version "3.12.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
||||
integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==
|
||||
dependencies:
|
||||
browserify-cipher "^1.0.0"
|
||||
browserify-sign "^4.0.0"
|
||||
create-ecdh "^4.0.0"
|
||||
create-hash "^1.1.0"
|
||||
create-hmac "^1.1.0"
|
||||
diffie-hellman "^5.0.0"
|
||||
inherits "^2.0.1"
|
||||
pbkdf2 "^3.0.3"
|
||||
public-encrypt "^4.0.0"
|
||||
randombytes "^2.0.0"
|
||||
randomfill "^1.0.3"
|
||||
|
||||
css-color-names@0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
|
||||
integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=
|
||||
|
||||
css-loader@^0.28.1:
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.11.tgz#c3f9864a700be2711bb5a2462b2389b1a392dab7"
|
||||
integrity sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==
|
||||
dependencies:
|
||||
babel-code-frame "^6.26.0"
|
||||
css-selector-tokenizer "^0.7.0"
|
||||
cssnano "^3.10.0"
|
||||
icss-utils "^2.1.0"
|
||||
loader-utils "^1.0.2"
|
||||
lodash.camelcase "^4.3.0"
|
||||
object-assign "^4.1.1"
|
||||
postcss "^5.0.6"
|
||||
postcss-modules-extract-imports "^1.2.0"
|
||||
postcss-modules-local-by-default "^1.2.0"
|
||||
postcss-modules-scope "^1.1.0"
|
||||
postcss-modules-values "^1.3.0"
|
||||
postcss-value-parser "^3.3.0"
|
||||
source-list-map "^2.0.0"
|
||||
|
||||
css-selector-tokenizer@^0.7.0:
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz#a177271a8bca5019172f4f891fc6eed9cbf68d5d"
|
||||
integrity sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==
|
||||
dependencies:
|
||||
cssesc "^0.1.0"
|
||||
fastparse "^1.1.1"
|
||||
regexpu-core "^1.0.0"
|
||||
|
||||
cssesc@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
|
||||
integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=
|
||||
|
||||
cssnano@^3.10.0:
|
||||
version "3.10.0"
|
||||
resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
|
||||
integrity sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=
|
||||
dependencies:
|
||||
autoprefixer "^6.3.1"
|
||||
decamelize "^1.1.2"
|
||||
defined "^1.0.0"
|
||||
has "^1.0.1"
|
||||
object-assign "^4.0.1"
|
||||
postcss "^5.0.14"
|
||||
postcss-calc "^5.2.0"
|
||||
postcss-colormin "^2.1.8"
|
||||
postcss-convert-values "^2.3.4"
|
||||
postcss-discard-comments "^2.0.4"
|
||||
postcss-discard-duplicates "^2.0.1"
|
||||
postcss-discard-empty "^2.0.1"
|
||||
postcss-discard-overridden "^0.1.1"
|
||||
postcss-discard-unused "^2.2.1"
|
||||
postcss-filter-plugins "^2.0.0"
|
||||
postcss-merge-idents "^2.1.5"
|
||||
postcss-merge-longhand "^2.0.1"
|
||||
postcss-merge-rules "^2.0.3"
|
||||
postcss-minify-font-values "^1.0.2"
|
||||
postcss-minify-gradients "^1.0.1"
|
||||
postcss-minify-params "^1.0.4"
|
||||
postcss-minify-selectors "^2.0.4"
|
||||
postcss-normalize-charset "^1.1.0"
|
||||
postcss-normalize-url "^3.0.7"
|
||||
postcss-ordered-values "^2.1.0"
|
||||
postcss-reduce-idents "^2.2.2"
|
||||
postcss-reduce-initial "^1.0.0"
|
||||
postcss-reduce-transforms "^1.0.3"
|
||||
postcss-svgo "^2.1.1"
|
||||
postcss-unique-selectors "^2.0.2"
|
||||
postcss-value-parser "^3.2.3"
|
||||
postcss-zindex "^2.0.1"
|
||||
|
||||
csso@~2.3.1:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85"
|
||||
integrity sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=
|
||||
dependencies:
|
||||
clap "^1.0.9"
|
||||
source-map "^0.5.3"
|
||||
|
||||
currently-unhandled@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
|
||||
integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
|
||||
dependencies:
|
||||
array-find-index "^1.0.1"
|
||||
|
||||
dashdash@^1.12.0:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
||||
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
debug@^2.2.0, debug@^2.3.3:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.2.6:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
|
||||
|
||||
decode-uri-component@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
|
||||
|
||||
deep-extend@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||
|
||||
define-property@^0.2.5:
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
|
||||
integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
|
||||
dependencies:
|
||||
is-descriptor "^0.1.0"
|
||||
|
||||
define-property@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
|
||||
integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
|
||||
dependencies:
|
||||
is-descriptor "^1.0.0"
|
||||
|
||||
define-property@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
|
||||
integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
|
||||
dependencies:
|
||||
is-descriptor "^1.0.2"
|
||||
isobject "^3.0.1"
|
||||
|
||||
defined@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
|
||||
integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
|
||||
|
||||
delegates@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||
|
||||
des.js@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
|
||||
integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==
|
||||
dependencies:
|
||||
inherits "^2.0.1"
|
||||
minimalistic-assert "^1.0.0"
|
||||
|
||||
detect-libc@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
|
||||
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
|
||||
|
||||
diffie-hellman@^5.0.0:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
|
||||
integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==
|
||||
dependencies:
|
||||
bn.js "^4.1.0"
|
||||
miller-rabin "^4.0.0"
|
||||
randombytes "^2.0.0"
|
||||
|
||||
domain-browser@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
|
||||
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
|
||||
dependencies:
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
electron-to-chromium@^1.2.7:
|
||||
version "1.3.306"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.306.tgz#e8265301d053d5f74e36cb876486830261fbe946"
|
||||
integrity sha512-frDqXvrIROoYvikSKTIKbHbzO6M3/qC6kCIt/1FOa9kALe++c4VAJnwjSFvf1tYLEUsP2n9XZ4XSCyqc3l7A/A==
|
||||
|
||||
elliptic@^6.0.0:
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
|
||||
integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
|
||||
dependencies:
|
||||
bn.js "^4.4.0"
|
||||
brorand "^1.0.1"
|
||||
hash.js "^1.0.0"
|
||||
hmac-drbg "^1.0.0"
|
||||
inherits "^2.0.1"
|
||||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.0"
|
||||
|
||||
emojis-list@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
|
||||
integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
|
||||
|
||||
enhanced-resolve@^3.3.0:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
|
||||
integrity sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
memory-fs "^0.4.0"
|
||||
object-assign "^4.0.1"
|
||||
tapable "^0.2.7"
|
||||
|
||||
errno@^0.1.3:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
|
||||
integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
|
||||
dependencies:
|
||||
prr "~1.0.1"
|
||||
|
||||
error-ex@^1.2.0:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
|
||||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
esprima@^2.6.0:
|
||||
version "2.7.3"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
|
||||
integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||
|
||||
events@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
|
||||
integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==
|
||||
|
||||
evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
|
||||
integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==
|
||||
dependencies:
|
||||
md5.js "^1.3.4"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
expand-brackets@^2.1.4:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
|
||||
integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
|
||||
dependencies:
|
||||
debug "^2.3.3"
|
||||
define-property "^0.2.5"
|
||||
extend-shallow "^2.0.1"
|
||||
posix-character-classes "^0.1.0"
|
||||
regex-not "^1.0.0"
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
extend-shallow@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
|
||||
integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
|
||||
dependencies:
|
||||
is-extendable "^0.1.0"
|
||||
|
||||
extend-shallow@^3.0.0, extend-shallow@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
|
||||
integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
|
||||
dependencies:
|
||||
assign-symbols "^1.0.0"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
||||
extglob@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
|
||||
integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
|
||||
dependencies:
|
||||
array-unique "^0.3.2"
|
||||
define-property "^1.0.0"
|
||||
expand-brackets "^2.1.4"
|
||||
extend-shallow "^2.0.1"
|
||||
fragment-cache "^0.2.1"
|
||||
regex-not "^1.0.0"
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
extract-text-webpack-plugin@^2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-2.1.2.tgz#756ef4efa8155c3681833fbc34da53b941746d6c"
|
||||
integrity sha1-dW7076gVXDaBgz+8NNpTuUF0bWw=
|
||||
dependencies:
|
||||
async "^2.1.2"
|
||||
loader-utils "^1.0.2"
|
||||
schema-utils "^0.3.0"
|
||||
webpack-sources "^1.0.1"
|
||||
|
||||
extsprintf@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
|
||||
|
||||
extsprintf@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
|
||||
|
||||
fast-deep-equal@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
|
||||
integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=
|
||||
|
||||
fast-deep-equal@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
||||
integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
|
||||
|
||||
fastparse@^1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
|
||||
integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
|
||||
|
||||
file-loader@^0.11.1:
|
||||
version "0.11.2"
|
||||
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.2.tgz#4ff1df28af38719a6098093b88c82c71d1794a34"
|
||||
integrity sha512-N+uhF3mswIFeziHQjGScJ/yHXYt3DiLBeC+9vWW+WjUBiClMSOlV1YrXQi+7KM2aA3Rn4Bybgv+uXFQbfkzpvg==
|
||||
dependencies:
|
||||
loader-utils "^1.0.2"
|
||||
|
||||
fill-range@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
|
||||
integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
|
||||
dependencies:
|
||||
extend-shallow "^2.0.1"
|
||||
is-number "^3.0.0"
|
||||
repeat-string "^1.6.1"
|
||||
to-regex-range "^2.1.0"
|
||||
|
||||
find-up@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
|
||||
integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
|
||||
dependencies:
|
||||
path-exists "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
flatten@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b"
|
||||
integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==
|
||||
|
||||
for-in@^0.1.3:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
|
||||
integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=
|
||||
|
||||
for-in@^1.0.1, for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
|
||||
|
||||
for-own@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
|
||||
integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
|
||||
dependencies:
|
||||
for-in "^1.0.1"
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
fragment-cache@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
|
||||
integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
|
||||
dependencies:
|
||||
map-cache "^0.2.2"
|
||||
|
||||
fs-minipass@^1.2.5:
|
||||
version "1.2.7"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
|
||||
integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
|
||||
dependencies:
|
||||
minipass "^2.6.0"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
fsevents@^1.2.7:
|
||||
version "1.2.9"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f"
|
||||
integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==
|
||||
dependencies:
|
||||
nan "^2.12.1"
|
||||
node-pre-gyp "^0.12.0"
|
||||
|
||||
fstream@^1.0.0, fstream@^1.0.12:
|
||||
version "1.0.12"
|
||||
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
|
||||
integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
inherits "~2.0.0"
|
||||
mkdirp ">=0.5 0"
|
||||
rimraf "2"
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
gauge@~2.7.3:
|
||||
version "2.7.4"
|
||||
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
|
||||
integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
|
||||
dependencies:
|
||||
aproba "^1.0.3"
|
||||
console-control-strings "^1.0.0"
|
||||
has-unicode "^2.0.0"
|
||||
object-assign "^4.1.0"
|
||||
signal-exit "^3.0.0"
|
||||
string-width "^1.0.1"
|
||||
strip-ansi "^3.0.1"
|
||||
wide-align "^1.1.0"
|
||||
|
||||
gaze@^1.0.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
|
||||
integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==
|
||||
dependencies:
|
||||
globule "^1.0.0"
|
||||
|
||||
get-caller-file@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
|
||||
integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
|
||||
|
||||
get-stdin@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
||||
integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
|
||||
|
||||
get-value@^2.0.3, get-value@^2.0.6:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
|
||||
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||
integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
glob-parent@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
|
||||
integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
|
||||
dependencies:
|
||||
is-glob "^3.1.0"
|
||||
path-dirname "^1.0.0"
|
||||
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
globule@^1.0.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
|
||||
integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==
|
||||
dependencies:
|
||||
glob "~7.1.1"
|
||||
lodash "~4.17.10"
|
||||
minimatch "~3.0.2"
|
||||
|
||||
graceful-fs@^4.1.11, graceful-fs@^4.1.2:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
|
||||
integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
|
||||
|
||||
har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
|
||||
|
||||
har-validator@~5.1.0:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
|
||||
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
|
||||
dependencies:
|
||||
ajv "^6.5.5"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
has-ansi@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
|
||||
integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
has-flag@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
|
||||
integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=
|
||||
|
||||
has-flag@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
||||
|
||||
has-unicode@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
|
||||
integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
|
||||
|
||||
has-value@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
|
||||
integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
|
||||
dependencies:
|
||||
get-value "^2.0.3"
|
||||
has-values "^0.1.4"
|
||||
isobject "^2.0.0"
|
||||
|
||||
has-value@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
|
||||
integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
|
||||
dependencies:
|
||||
get-value "^2.0.6"
|
||||
has-values "^1.0.0"
|
||||
isobject "^3.0.0"
|
||||
|
||||
has-values@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
|
||||
integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
|
||||
|
||||
has-values@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
|
||||
integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
|
||||
dependencies:
|
||||
is-number "^3.0.0"
|
||||
kind-of "^4.0.0"
|
||||
|
||||
has@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
hash-base@^3.0.0:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918"
|
||||
integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=
|
||||
dependencies:
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
hash.js@^1.0.0, hash.js@^1.0.3:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
|
||||
integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
|
||||
dependencies:
|
||||
inherits "^2.0.3"
|
||||
minimalistic-assert "^1.0.1"
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
||||
integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
|
||||
dependencies:
|
||||
hash.js "^1.0.3"
|
||||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hosted-git-info@^2.1.4:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c"
|
||||
integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==
|
||||
|
||||
html-comment-regex@^1.1.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7"
|
||||
integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==
|
||||
|
||||
http-signature@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
||||
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
https-browserify@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||
|
||||
iconv-lite@^0.4.4:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
icss-replace-symbols@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
|
||||
integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=
|
||||
|
||||
icss-utils@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962"
|
||||
integrity sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=
|
||||
dependencies:
|
||||
postcss "^6.0.1"
|
||||
|
||||
ieee754@^1.1.4:
|
||||
version "1.1.13"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
|
||||
integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
|
||||
|
||||
ignore-walk@^3.0.1:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37"
|
||||
integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==
|
||||
dependencies:
|
||||
minimatch "^3.0.4"
|
||||
|
||||
in-publish@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
|
||||
integrity sha1-4g/146KvwmkDILbcVSaCqcf631E=
|
||||
|
||||
indent-string@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
|
||||
integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
|
||||
dependencies:
|
||||
repeating "^2.0.0"
|
||||
|
||||
indexes-of@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
|
||||
integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
inherits@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
|
||||
integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
|
||||
|
||||
inherits@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
ini@~1.3.0:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
|
||||
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
|
||||
|
||||
interpret@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
|
||||
integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
|
||||
|
||||
invert-kv@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
|
||||
integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
|
||||
|
||||
is-absolute-url@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
|
||||
integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=
|
||||
|
||||
is-accessor-descriptor@^0.1.6:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
|
||||
integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
|
||||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
|
||||
is-accessor-descriptor@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
|
||||
integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
|
||||
dependencies:
|
||||
kind-of "^6.0.0"
|
||||
|
||||
is-arrayish@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
||||
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
|
||||
|
||||
is-binary-path@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
|
||||
integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
|
||||
dependencies:
|
||||
binary-extensions "^1.0.0"
|
||||
|
||||
is-buffer@^1.1.5:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||
|
||||
is-data-descriptor@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
|
||||
integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
|
||||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
|
||||
is-data-descriptor@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
|
||||
integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
|
||||
dependencies:
|
||||
kind-of "^6.0.0"
|
||||
|
||||
is-descriptor@^0.1.0:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
|
||||
integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
|
||||
dependencies:
|
||||
is-accessor-descriptor "^0.1.6"
|
||||
is-data-descriptor "^0.1.4"
|
||||
kind-of "^5.0.0"
|
||||
|
||||
is-descriptor@^1.0.0, is-descriptor@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
|
||||
integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
|
||||
dependencies:
|
||||
is-accessor-descriptor "^1.0.0"
|
||||
is-data-descriptor "^1.0.0"
|
||||
kind-of "^6.0.2"
|
||||
|
||||
is-extendable@^0.1.0, is-extendable@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
|
||||
integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
|
||||
|
||||
is-extendable@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
|
||||
integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
|
||||
dependencies:
|
||||
is-plain-object "^2.0.4"
|
||||
|
||||
is-extglob@^2.1.0, is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
|
||||
|
||||
is-finite@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
|
||||
integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
|
||||
dependencies:
|
||||
number-is-nan "^1.0.0"
|
||||
|
||||
is-fullwidth-code-point@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
|
||||
integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
|
||||
dependencies:
|
||||
number-is-nan "^1.0.0"
|
||||
|
||||
is-fullwidth-code-point@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
|
||||
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
|
||||
|
||||
is-glob@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
|
||||
integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
|
||||
dependencies:
|
||||
is-extglob "^2.1.0"
|
||||
|
||||
is-glob@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
|
||||
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-number@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
|
||||
integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
|
||||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
|
||||
is-plain-obj@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
||||
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
|
||||
|
||||
is-plain-object@^2.0.3, is-plain-object@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
|
||||
integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
|
||||
dependencies:
|
||||
isobject "^3.0.1"
|
||||
|
||||
is-svg@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
|
||||
integrity sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=
|
||||
dependencies:
|
||||
html-comment-regex "^1.1.0"
|
||||
|
||||
is-typedarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
|
||||
|
||||
is-utf8@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
||||
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
|
||||
|
||||
is-windows@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
|
||||
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
|
||||
|
||||
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
|
||||
|
||||
isobject@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
|
||||
integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
|
||||
dependencies:
|
||||
isarray "1.0.0"
|
||||
|
||||
isobject@^3.0.0, isobject@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
||||
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
|
||||
|
||||
isstream@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
|
||||
|
||||
js-base64@^2.1.8, js-base64@^2.1.9:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
|
||||
integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
|
||||
|
||||
js-tokens@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
||||
integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
|
||||
|
||||
js-yaml@~3.7.0:
|
||||
version "3.7.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
|
||||
integrity sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
esprima "^2.6.0"
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||
|
||||
jsesc@~0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
||||
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
|
||||
|
||||
json-loader@^0.5.4:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d"
|
||||
integrity sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==
|
||||
|
||||
json-schema-traverse@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
|
||||
integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=
|
||||
|
||||
json-schema-traverse@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
|
||||
|
||||
json-schema@0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
|
||||
|
||||
json-stable-stringify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
|
||||
integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=
|
||||
dependencies:
|
||||
jsonify "~0.0.0"
|
||||
|
||||
json-stringify-safe@~5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||
|
||||
json5@^0.5.0, json5@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
|
||||
integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
|
||||
|
||||
json5@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
|
||||
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
|
||||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
|
||||
jsonify@~0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
|
||||
integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
|
||||
|
||||
jsprim@^1.2.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
||||
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
|
||||
dependencies:
|
||||
assert-plus "1.0.0"
|
||||
extsprintf "1.3.0"
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
|
||||
integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
|
||||
dependencies:
|
||||
is-buffer "^1.1.5"
|
||||
|
||||
kind-of@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
|
||||
integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
|
||||
dependencies:
|
||||
is-buffer "^1.1.5"
|
||||
|
||||
kind-of@^5.0.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
|
||||
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
|
||||
|
||||
kind-of@^6.0.0, kind-of@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
|
||||
integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
|
||||
|
||||
lazy-cache@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
|
||||
integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4=
|
||||
|
||||
lcid@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
|
||||
integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
|
||||
dependencies:
|
||||
invert-kv "^1.0.0"
|
||||
|
||||
load-json-file@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
|
||||
integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
parse-json "^2.2.0"
|
||||
pify "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
strip-bom "^2.0.0"
|
||||
|
||||
loader-runner@^2.3.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
|
||||
integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
|
||||
|
||||
loader-utils@^0.2.16:
|
||||
version "0.2.17"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
|
||||
integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=
|
||||
dependencies:
|
||||
big.js "^3.1.3"
|
||||
emojis-list "^2.0.0"
|
||||
json5 "^0.5.0"
|
||||
object-assign "^4.0.1"
|
||||
|
||||
loader-utils@^1.0.1, loader-utils@^1.0.2:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
|
||||
integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
|
||||
dependencies:
|
||||
big.js "^5.2.2"
|
||||
emojis-list "^2.0.0"
|
||||
json5 "^1.0.1"
|
||||
|
||||
lodash.camelcase@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
||||
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
|
||||
|
||||
lodash.memoize@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||
|
||||
lodash.tail@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
|
||||
integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=
|
||||
|
||||
lodash.uniq@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||
|
||||
lodash@^4.0.0, lodash@^4.17.14, lodash@^4.17.15, lodash@~4.17.10:
|
||||
version "4.17.19"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
|
||||
|
||||
longest@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
||||
integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
|
||||
|
||||
loud-rejection@^1.0.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
||||
integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
|
||||
dependencies:
|
||||
currently-unhandled "^0.4.1"
|
||||
signal-exit "^3.0.0"
|
||||
|
||||
lru-cache@^4.0.1:
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
|
||||
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
|
||||
dependencies:
|
||||
pseudomap "^1.0.2"
|
||||
yallist "^2.1.2"
|
||||
|
||||
map-cache@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
|
||||
integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
|
||||
|
||||
map-obj@^1.0.0, map-obj@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
|
||||
integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
|
||||
|
||||
map-visit@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
|
||||
integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
|
||||
dependencies:
|
||||
object-visit "^1.0.0"
|
||||
|
||||
math-expression-evaluator@^1.2.14:
|
||||
version "1.2.17"
|
||||
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
|
||||
integrity sha1-3oGf282E3M2PrlnGrreWFbnSZqw=
|
||||
|
||||
md5.js@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||
integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
|
||||
dependencies:
|
||||
hash-base "^3.0.0"
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.1.2"
|
||||
|
||||
memory-fs@^0.4.0, memory-fs@~0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
|
||||
integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=
|
||||
dependencies:
|
||||
errno "^0.1.3"
|
||||
readable-stream "^2.0.1"
|
||||
|
||||
meow@^3.7.0:
|
||||
version "3.7.0"
|
||||
resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
|
||||
integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
|
||||
dependencies:
|
||||
camelcase-keys "^2.0.0"
|
||||
decamelize "^1.1.2"
|
||||
loud-rejection "^1.0.0"
|
||||
map-obj "^1.0.1"
|
||||
minimist "^1.1.3"
|
||||
normalize-package-data "^2.3.4"
|
||||
object-assign "^4.0.1"
|
||||
read-pkg-up "^1.0.1"
|
||||
redent "^1.0.0"
|
||||
trim-newlines "^1.0.0"
|
||||
|
||||
micromatch@^3.1.10, micromatch@^3.1.4:
|
||||
version "3.1.10"
|
||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
|
||||
integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
|
||||
dependencies:
|
||||
arr-diff "^4.0.0"
|
||||
array-unique "^0.3.2"
|
||||
braces "^2.3.1"
|
||||
define-property "^2.0.2"
|
||||
extend-shallow "^3.0.2"
|
||||
extglob "^2.0.4"
|
||||
fragment-cache "^0.2.1"
|
||||
kind-of "^6.0.2"
|
||||
nanomatch "^1.2.9"
|
||||
object.pick "^1.3.0"
|
||||
regex-not "^1.0.0"
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.2"
|
||||
|
||||
miller-rabin@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
|
||||
integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==
|
||||
dependencies:
|
||||
bn.js "^4.0.0"
|
||||
brorand "^1.0.1"
|
||||
|
||||
mime-db@1.42.0:
|
||||
version "1.42.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac"
|
||||
integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==
|
||||
|
||||
mime-types@^2.1.12, mime-types@~2.1.19:
|
||||
version "2.1.25"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437"
|
||||
integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==
|
||||
dependencies:
|
||||
mime-db "1.42.0"
|
||||
|
||||
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
|
||||
integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
|
||||
|
||||
minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
|
||||
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
|
||||
|
||||
minimatch@^3.0.4, minimatch@~3.0.2:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
||||
|
||||
minimist@^1.1.3, minimist@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
||||
minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
|
||||
integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
|
||||
dependencies:
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.0"
|
||||
|
||||
minizlib@^1.2.1:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
|
||||
integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==
|
||||
dependencies:
|
||||
minipass "^2.9.0"
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
||||
integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
|
||||
dependencies:
|
||||
for-in "^1.0.2"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
mixin-object@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
|
||||
integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=
|
||||
dependencies:
|
||||
for-in "^0.1.3"
|
||||
is-extendable "^0.1.1"
|
||||
|
||||
"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
ms@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
nan@^2.12.1, nan@^2.13.2:
|
||||
version "2.14.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
||||
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
||||
integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
|
||||
dependencies:
|
||||
arr-diff "^4.0.0"
|
||||
array-unique "^0.3.2"
|
||||
define-property "^2.0.2"
|
||||
extend-shallow "^3.0.2"
|
||||
fragment-cache "^0.2.1"
|
||||
is-windows "^1.0.2"
|
||||
kind-of "^6.0.2"
|
||||
object.pick "^1.3.0"
|
||||
regex-not "^1.0.0"
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
needle@^2.2.1:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
|
||||
integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
|
||||
dependencies:
|
||||
debug "^3.2.6"
|
||||
iconv-lite "^0.4.4"
|
||||
sax "^1.2.4"
|
||||
|
||||
neo-async@^2.5.0:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
|
||||
integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
|
||||
|
||||
node-gyp@^3.8.0:
|
||||
version "3.8.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
|
||||
integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==
|
||||
dependencies:
|
||||
fstream "^1.0.0"
|
||||
glob "^7.0.3"
|
||||
graceful-fs "^4.1.2"
|
||||
mkdirp "^0.5.0"
|
||||
nopt "2 || 3"
|
||||
npmlog "0 || 1 || 2 || 3 || 4"
|
||||
osenv "0"
|
||||
request "^2.87.0"
|
||||
rimraf "2"
|
||||
semver "~5.3.0"
|
||||
tar "^2.0.0"
|
||||
which "1"
|
||||
|
||||
node-libs-browser@^2.0.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
|
||||
integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
|
||||
dependencies:
|
||||
assert "^1.1.1"
|
||||
browserify-zlib "^0.2.0"
|
||||
buffer "^4.3.0"
|
||||
console-browserify "^1.1.0"
|
||||
constants-browserify "^1.0.0"
|
||||
crypto-browserify "^3.11.0"
|
||||
domain-browser "^1.1.1"
|
||||
events "^3.0.0"
|
||||
https-browserify "^1.0.0"
|
||||
os-browserify "^0.3.0"
|
||||
path-browserify "0.0.1"
|
||||
process "^0.11.10"
|
||||
punycode "^1.2.4"
|
||||
querystring-es3 "^0.2.0"
|
||||
readable-stream "^2.3.3"
|
||||
stream-browserify "^2.0.1"
|
||||
stream-http "^2.7.2"
|
||||
string_decoder "^1.0.0"
|
||||
timers-browserify "^2.0.4"
|
||||
tty-browserify "0.0.0"
|
||||
url "^0.11.0"
|
||||
util "^0.11.0"
|
||||
vm-browserify "^1.0.1"
|
||||
|
||||
node-pre-gyp@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
|
||||
integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
|
||||
dependencies:
|
||||
detect-libc "^1.0.2"
|
||||
mkdirp "^0.5.1"
|
||||
needle "^2.2.1"
|
||||
nopt "^4.0.1"
|
||||
npm-packlist "^1.1.6"
|
||||
npmlog "^4.0.2"
|
||||
rc "^1.2.7"
|
||||
rimraf "^2.6.1"
|
||||
semver "^5.3.0"
|
||||
tar "^4"
|
||||
|
||||
node-sass@^4.13.1:
|
||||
version "4.13.1"
|
||||
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.13.1.tgz#9db5689696bb2eec2c32b98bfea4c7a2e992d0a3"
|
||||
integrity sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==
|
||||
dependencies:
|
||||
async-foreach "^0.1.3"
|
||||
chalk "^1.1.1"
|
||||
cross-spawn "^3.0.0"
|
||||
gaze "^1.0.0"
|
||||
get-stdin "^4.0.1"
|
||||
glob "^7.0.3"
|
||||
in-publish "^2.0.0"
|
||||
lodash "^4.17.15"
|
||||
meow "^3.7.0"
|
||||
mkdirp "^0.5.1"
|
||||
nan "^2.13.2"
|
||||
node-gyp "^3.8.0"
|
||||
npmlog "^4.0.0"
|
||||
request "^2.88.0"
|
||||
sass-graph "^2.2.4"
|
||||
stdout-stream "^1.4.0"
|
||||
"true-case-path" "^1.0.2"
|
||||
|
||||
"nopt@2 || 3":
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
|
||||
integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
nopt@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
|
||||
integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
osenv "^0.1.4"
|
||||
|
||||
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
|
||||
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
|
||||
dependencies:
|
||||
hosted-git-info "^2.1.4"
|
||||
resolve "^1.10.0"
|
||||
semver "2 || 3 || 4 || 5"
|
||||
validate-npm-package-license "^3.0.1"
|
||||
|
||||
normalize-path@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
|
||||
integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
|
||||
dependencies:
|
||||
remove-trailing-separator "^1.0.1"
|
||||
|
||||
normalize-path@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||
|
||||
normalize-range@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
|
||||
|
||||
normalize-url@^1.4.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c"
|
||||
integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=
|
||||
dependencies:
|
||||
object-assign "^4.0.1"
|
||||
prepend-http "^1.0.0"
|
||||
query-string "^4.1.0"
|
||||
sort-keys "^1.0.0"
|
||||
|
||||
npm-bundled@^1.0.1:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
|
||||
integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
|
||||
|
||||
npm-packlist@^1.1.6:
|
||||
version "1.4.6"
|
||||
resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.6.tgz#53ba3ed11f8523079f1457376dd379ee4ea42ff4"
|
||||
integrity sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==
|
||||
dependencies:
|
||||
ignore-walk "^3.0.1"
|
||||
npm-bundled "^1.0.1"
|
||||
|
||||
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
|
||||
integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
|
||||
dependencies:
|
||||
are-we-there-yet "~1.1.2"
|
||||
console-control-strings "~1.1.0"
|
||||
gauge "~2.7.3"
|
||||
set-blocking "~2.0.0"
|
||||
|
||||
num2fraction@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
|
||||
integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=
|
||||
|
||||
number-is-nan@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-copy@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
|
||||
integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
|
||||
dependencies:
|
||||
copy-descriptor "^0.1.0"
|
||||
define-property "^0.2.5"
|
||||
kind-of "^3.0.3"
|
||||
|
||||
object-visit@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
|
||||
integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
|
||||
dependencies:
|
||||
isobject "^3.0.0"
|
||||
|
||||
object.pick@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
|
||||
integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
|
||||
dependencies:
|
||||
isobject "^3.0.1"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
os-browserify@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
|
||||
integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
|
||||
|
||||
os-homedir@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
|
||||
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
|
||||
|
||||
os-locale@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
|
||||
integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
|
||||
dependencies:
|
||||
lcid "^1.0.0"
|
||||
|
||||
os-tmpdir@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
||||
|
||||
osenv@0, osenv@^0.1.4:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
|
||||
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
|
||||
dependencies:
|
||||
os-homedir "^1.0.0"
|
||||
os-tmpdir "^1.0.0"
|
||||
|
||||
pako@~1.0.5:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
|
||||
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
|
||||
|
||||
parse-asn1@^5.0.0:
|
||||
version "5.1.5"
|
||||
resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e"
|
||||
integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==
|
||||
dependencies:
|
||||
asn1.js "^4.0.0"
|
||||
browserify-aes "^1.0.0"
|
||||
create-hash "^1.1.0"
|
||||
evp_bytestokey "^1.0.0"
|
||||
pbkdf2 "^3.0.3"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
parse-json@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
|
||||
integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
|
||||
dependencies:
|
||||
error-ex "^1.2.0"
|
||||
|
||||
pascalcase@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
|
||||
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
|
||||
|
||||
path-browserify@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
|
||||
integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
|
||||
|
||||
path-dirname@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
|
||||
integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
|
||||
|
||||
path-exists@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
|
||||
integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
|
||||
dependencies:
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
path-parse@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
||||
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
|
||||
|
||||
path-type@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
|
||||
integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
pify "^2.0.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
pbkdf2@^3.0.3:
|
||||
version "3.0.17"
|
||||
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
|
||||
integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==
|
||||
dependencies:
|
||||
create-hash "^1.1.2"
|
||||
create-hmac "^1.1.4"
|
||||
ripemd160 "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
pify@^2.0.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
|
||||
|
||||
pify@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
|
||||
|
||||
pinkie-promise@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
|
||||
integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
|
||||
dependencies:
|
||||
pinkie "^2.0.0"
|
||||
|
||||
pinkie@^2.0.0:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
|
||||
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
|
||||
|
||||
posix-character-classes@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
|
||||
|
||||
postcss-calc@^5.2.0:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
|
||||
integrity sha1-d7rnypKK2FcW4v2kLyYb98HWW14=
|
||||
dependencies:
|
||||
postcss "^5.0.2"
|
||||
postcss-message-helpers "^2.0.0"
|
||||
reduce-css-calc "^1.2.6"
|
||||
|
||||
postcss-colormin@^2.1.8:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b"
|
||||
integrity sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=
|
||||
dependencies:
|
||||
colormin "^1.0.5"
|
||||
postcss "^5.0.13"
|
||||
postcss-value-parser "^3.2.3"
|
||||
|
||||
postcss-convert-values@^2.3.4:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d"
|
||||
integrity sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=
|
||||
dependencies:
|
||||
postcss "^5.0.11"
|
||||
postcss-value-parser "^3.1.2"
|
||||
|
||||
postcss-discard-comments@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d"
|
||||
integrity sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=
|
||||
dependencies:
|
||||
postcss "^5.0.14"
|
||||
|
||||
postcss-discard-duplicates@^2.0.1:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932"
|
||||
integrity sha1-uavye4isGIFYpesSq8riAmO5GTI=
|
||||
dependencies:
|
||||
postcss "^5.0.4"
|
||||
|
||||
postcss-discard-empty@^2.0.1:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5"
|
||||
integrity sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=
|
||||
dependencies:
|
||||
postcss "^5.0.14"
|
||||
|
||||
postcss-discard-overridden@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58"
|
||||
integrity sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=
|
||||
dependencies:
|
||||
postcss "^5.0.16"
|
||||
|
||||
postcss-discard-unused@^2.2.1:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433"
|
||||
integrity sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=
|
||||
dependencies:
|
||||
postcss "^5.0.14"
|
||||
uniqs "^2.0.0"
|
||||
|
||||
postcss-filter-plugins@^2.0.0:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz#82245fdf82337041645e477114d8e593aa18b8ec"
|
||||
integrity sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==
|
||||
dependencies:
|
||||
postcss "^5.0.4"
|
||||
|
||||
postcss-merge-idents@^2.1.5:
|
||||
version "2.1.7"
|
||||
resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
|
||||
integrity sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=
|
||||
dependencies:
|
||||
has "^1.0.1"
|
||||
postcss "^5.0.10"
|
||||
postcss-value-parser "^3.1.1"
|
||||
|
||||
postcss-merge-longhand@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658"
|
||||
integrity sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=
|
||||
dependencies:
|
||||
postcss "^5.0.4"
|
||||
|
||||
postcss-merge-rules@^2.0.3:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721"
|
||||
integrity sha1-0d9d+qexrMO+VT8OnhDofGG19yE=
|
||||
dependencies:
|
||||
browserslist "^1.5.2"
|
||||
caniuse-api "^1.5.2"
|
||||
postcss "^5.0.4"
|
||||
postcss-selector-parser "^2.2.2"
|
||||
vendors "^1.0.0"
|
||||
|
||||
postcss-message-helpers@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e"
|
||||
integrity sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=
|
||||
|
||||
postcss-minify-font-values@^1.0.2:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69"
|
||||
integrity sha1-S1jttWZB66fIR0qzUmyv17vey2k=
|
||||
dependencies:
|
||||
object-assign "^4.0.1"
|
||||
postcss "^5.0.4"
|
||||
postcss-value-parser "^3.0.2"
|
||||
|
||||
postcss-minify-gradients@^1.0.1:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1"
|
||||
integrity sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=
|
||||
dependencies:
|
||||
postcss "^5.0.12"
|
||||
postcss-value-parser "^3.3.0"
|
||||
|
||||
postcss-minify-params@^1.0.4:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3"
|
||||
integrity sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=
|
||||
dependencies:
|
||||
alphanum-sort "^1.0.1"
|
||||
postcss "^5.0.2"
|
||||
postcss-value-parser "^3.0.2"
|
||||
uniqs "^2.0.0"
|
||||
|
||||
postcss-minify-selectors@^2.0.4:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf"
|
||||
integrity sha1-ssapjAByz5G5MtGkllCBFDEXNb8=
|
||||
dependencies:
|
||||
alphanum-sort "^1.0.2"
|
||||
has "^1.0.1"
|
||||
postcss "^5.0.14"
|
||||
postcss-selector-parser "^2.0.0"
|
||||
|
||||
postcss-modules-extract-imports@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz#dc87e34148ec7eab5f791f7cd5849833375b741a"
|
||||
integrity sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==
|
||||
dependencies:
|
||||
postcss "^6.0.1"
|
||||
|
||||
postcss-modules-local-by-default@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
|
||||
integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=
|
||||
dependencies:
|
||||
css-selector-tokenizer "^0.7.0"
|
||||
postcss "^6.0.1"
|
||||
|
||||
postcss-modules-scope@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
|
||||
integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A=
|
||||
dependencies:
|
||||
css-selector-tokenizer "^0.7.0"
|
||||
postcss "^6.0.1"
|
||||
|
||||
postcss-modules-values@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20"
|
||||
integrity sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=
|
||||
dependencies:
|
||||
icss-replace-symbols "^1.1.0"
|
||||
postcss "^6.0.1"
|
||||
|
||||
postcss-normalize-charset@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1"
|
||||
integrity sha1-757nEhLX/nWceO0WL2HtYrXLk/E=
|
||||
dependencies:
|
||||
postcss "^5.0.5"
|
||||
|
||||
postcss-normalize-url@^3.0.7:
|
||||
version "3.0.8"
|
||||
resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222"
|
||||
integrity sha1-EI90s/L82viRov+j6kWSJ5/HgiI=
|
||||
dependencies:
|
||||
is-absolute-url "^2.0.0"
|
||||
normalize-url "^1.4.0"
|
||||
postcss "^5.0.14"
|
||||
postcss-value-parser "^3.2.3"
|
||||
|
||||
postcss-ordered-values@^2.1.0:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d"
|
||||
integrity sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=
|
||||
dependencies:
|
||||
postcss "^5.0.4"
|
||||
postcss-value-parser "^3.0.1"
|
||||
|
||||
postcss-reduce-idents@^2.2.2:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3"
|
||||
integrity sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=
|
||||
dependencies:
|
||||
postcss "^5.0.4"
|
||||
postcss-value-parser "^3.0.2"
|
||||
|
||||
postcss-reduce-initial@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea"
|
||||
integrity sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=
|
||||
dependencies:
|
||||
postcss "^5.0.4"
|
||||
|
||||
postcss-reduce-transforms@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1"
|
||||
integrity sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=
|
||||
dependencies:
|
||||
has "^1.0.1"
|
||||
postcss "^5.0.8"
|
||||
postcss-value-parser "^3.0.1"
|
||||
|
||||
postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90"
|
||||
integrity sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=
|
||||
dependencies:
|
||||
flatten "^1.0.2"
|
||||
indexes-of "^1.0.1"
|
||||
uniq "^1.0.1"
|
||||
|
||||
postcss-svgo@^2.1.1:
|
||||
version "2.1.6"
|
||||
resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d"
|
||||
integrity sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=
|
||||
dependencies:
|
||||
is-svg "^2.0.0"
|
||||
postcss "^5.0.14"
|
||||
postcss-value-parser "^3.2.3"
|
||||
svgo "^0.7.0"
|
||||
|
||||
postcss-unique-selectors@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d"
|
||||
integrity sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=
|
||||
dependencies:
|
||||
alphanum-sort "^1.0.1"
|
||||
postcss "^5.0.4"
|
||||
uniqs "^2.0.0"
|
||||
|
||||
postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
|
||||
integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
|
||||
|
||||
postcss-zindex@^2.0.1:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22"
|
||||
integrity sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=
|
||||
dependencies:
|
||||
has "^1.0.1"
|
||||
postcss "^5.0.4"
|
||||
uniqs "^2.0.0"
|
||||
|
||||
postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16:
|
||||
version "5.2.18"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5"
|
||||
integrity sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==
|
||||
dependencies:
|
||||
chalk "^1.1.3"
|
||||
js-base64 "^2.1.9"
|
||||
source-map "^0.5.6"
|
||||
supports-color "^3.2.3"
|
||||
|
||||
postcss@^6.0.1:
|
||||
version "6.0.23"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
|
||||
integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==
|
||||
dependencies:
|
||||
chalk "^2.4.1"
|
||||
source-map "^0.6.1"
|
||||
supports-color "^5.4.0"
|
||||
|
||||
prepend-http@^1.0.0:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
process@^0.11.10:
|
||||
version "0.11.10"
|
||||
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
|
||||
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
|
||||
|
||||
prr@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
||||
integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
|
||||
|
||||
pseudomap@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
||||
|
||||
psl@^1.1.24:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2"
|
||||
integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==
|
||||
|
||||
public-encrypt@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
|
||||
integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==
|
||||
dependencies:
|
||||
bn.js "^4.1.0"
|
||||
browserify-rsa "^4.0.0"
|
||||
create-hash "^1.1.0"
|
||||
parse-asn1 "^5.0.0"
|
||||
randombytes "^2.0.1"
|
||||
safe-buffer "^5.1.2"
|
||||
|
||||
punycode@1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||
integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
|
||||
|
||||
punycode@^1.2.4, punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
||||
|
||||
punycode@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
q@^1.1.2:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
||||
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
|
||||
integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
|
||||
|
||||
query-string@^4.1.0:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
|
||||
integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s=
|
||||
dependencies:
|
||||
object-assign "^4.1.0"
|
||||
strict-uri-encode "^1.0.0"
|
||||
|
||||
querystring-es3@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
||||
integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=
|
||||
|
||||
querystring@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
|
||||
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
|
||||
|
||||
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||
integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
|
||||
dependencies:
|
||||
safe-buffer "^5.1.0"
|
||||
|
||||
randomfill@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458"
|
||||
integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==
|
||||
dependencies:
|
||||
randombytes "^2.0.5"
|
||||
safe-buffer "^5.1.0"
|
||||
|
||||
rc@^1.2.7:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
|
||||
dependencies:
|
||||
deep-extend "^0.6.0"
|
||||
ini "~1.3.0"
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
read-pkg-up@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
|
||||
integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
|
||||
dependencies:
|
||||
find-up "^1.0.0"
|
||||
read-pkg "^1.0.0"
|
||||
|
||||
read-pkg@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
|
||||
integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
|
||||
dependencies:
|
||||
load-json-file "^1.0.0"
|
||||
normalize-package-data "^2.3.2"
|
||||
path-type "^1.0.0"
|
||||
|
||||
readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.3.3, readable-stream@^2.3.6:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
||||
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readdirp@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
|
||||
integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
|
||||
dependencies:
|
||||
graceful-fs "^4.1.11"
|
||||
micromatch "^3.1.10"
|
||||
readable-stream "^2.0.2"
|
||||
|
||||
redent@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
|
||||
integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
|
||||
dependencies:
|
||||
indent-string "^2.1.0"
|
||||
strip-indent "^1.0.1"
|
||||
|
||||
reduce-css-calc@^1.2.6:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
|
||||
integrity sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=
|
||||
dependencies:
|
||||
balanced-match "^0.4.2"
|
||||
math-expression-evaluator "^1.2.14"
|
||||
reduce-function-call "^1.0.1"
|
||||
|
||||
reduce-function-call@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.3.tgz#60350f7fb252c0a67eb10fd4694d16909971300f"
|
||||
integrity sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
|
||||
regenerate@^1.2.1:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
|
||||
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
|
||||
|
||||
regex-not@^1.0.0, regex-not@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
|
||||
integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
|
||||
dependencies:
|
||||
extend-shallow "^3.0.2"
|
||||
safe-regex "^1.1.0"
|
||||
|
||||
regexpu-core@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
|
||||
integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=
|
||||
dependencies:
|
||||
regenerate "^1.2.1"
|
||||
regjsgen "^0.2.0"
|
||||
regjsparser "^0.1.4"
|
||||
|
||||
regjsgen@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
|
||||
integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=
|
||||
|
||||
regjsparser@^0.1.4:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
|
||||
integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=
|
||||
dependencies:
|
||||
jsesc "~0.5.0"
|
||||
|
||||
remove-trailing-separator@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
|
||||
integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
|
||||
|
||||
repeat-element@^1.1.2:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
|
||||
integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
|
||||
|
||||
repeat-string@^1.5.2, repeat-string@^1.6.1:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
|
||||
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
|
||||
|
||||
repeating@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
|
||||
integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
|
||||
dependencies:
|
||||
is-finite "^1.0.0"
|
||||
|
||||
request@^2.87.0, request@^2.88.0:
|
||||
version "2.88.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
|
||||
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.0"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.4.3"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
|
||||
|
||||
require-main-filename@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
|
||||
integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
|
||||
|
||||
resolve-url@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
||||
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
|
||||
|
||||
resolve@^1.10.0:
|
||||
version "1.12.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6"
|
||||
integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
ret@~0.1.10:
|
||||
version "0.1.15"
|
||||
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
|
||||
|
||||
right-align@^0.1.1:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
|
||||
integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8=
|
||||
dependencies:
|
||||
align-text "^0.1.1"
|
||||
|
||||
rimraf@2, rimraf@^2.6.1:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
|
||||
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
ripemd160@^2.0.0, ripemd160@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
|
||||
integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
|
||||
dependencies:
|
||||
hash-base "^3.0.0"
|
||||
inherits "^2.0.1"
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
||||
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
||||
|
||||
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-regex@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
|
||||
integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
|
||||
dependencies:
|
||||
ret "~0.1.10"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
sass-graph@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
|
||||
integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=
|
||||
dependencies:
|
||||
glob "^7.0.0"
|
||||
lodash "^4.0.0"
|
||||
scss-tokenizer "^0.2.3"
|
||||
yargs "^7.0.0"
|
||||
|
||||
sass-loader@^6.0.3:
|
||||
version "6.0.7"
|
||||
resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.7.tgz#dd2fdb3e7eeff4a53f35ba6ac408715488353d00"
|
||||
integrity sha512-JoiyD00Yo1o61OJsoP2s2kb19L1/Y2p3QFcCdWdF6oomBGKVYuZyqHWemRBfQ2uGYsk+CH3eCguXNfpjzlcpaA==
|
||||
dependencies:
|
||||
clone-deep "^2.0.1"
|
||||
loader-utils "^1.0.1"
|
||||
lodash.tail "^4.1.1"
|
||||
neo-async "^2.5.0"
|
||||
pify "^3.0.0"
|
||||
|
||||
sax@^1.2.4, sax@~1.2.1:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
schema-utils@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"
|
||||
integrity sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=
|
||||
dependencies:
|
||||
ajv "^5.0.0"
|
||||
|
||||
scss-tokenizer@^0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
|
||||
integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE=
|
||||
dependencies:
|
||||
js-base64 "^2.1.8"
|
||||
source-map "^0.4.2"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.3.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
||||
semver@~5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
||||
integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
|
||||
|
||||
set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
set-value@^2.0.0, set-value@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
|
||||
integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
|
||||
dependencies:
|
||||
extend-shallow "^2.0.1"
|
||||
is-extendable "^0.1.1"
|
||||
is-plain-object "^2.0.3"
|
||||
split-string "^3.0.1"
|
||||
|
||||
setimmediate@^1.0.4:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
||||
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
|
||||
|
||||
sha.js@^2.4.0, sha.js@^2.4.8:
|
||||
version "2.4.11"
|
||||
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
|
||||
integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
|
||||
dependencies:
|
||||
inherits "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
shallow-clone@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571"
|
||||
integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==
|
||||
dependencies:
|
||||
is-extendable "^0.1.1"
|
||||
kind-of "^5.0.0"
|
||||
mixin-object "^2.0.1"
|
||||
|
||||
signal-exit@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
|
||||
|
||||
snapdragon-node@^2.0.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
|
||||
integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
|
||||
dependencies:
|
||||
define-property "^1.0.0"
|
||||
isobject "^3.0.0"
|
||||
snapdragon-util "^3.0.1"
|
||||
|
||||
snapdragon-util@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
|
||||
integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
|
||||
dependencies:
|
||||
kind-of "^3.2.0"
|
||||
|
||||
snapdragon@^0.8.1:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
|
||||
integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
|
||||
dependencies:
|
||||
base "^0.11.1"
|
||||
debug "^2.2.0"
|
||||
define-property "^0.2.5"
|
||||
extend-shallow "^2.0.1"
|
||||
map-cache "^0.2.2"
|
||||
source-map "^0.5.6"
|
||||
source-map-resolve "^0.5.0"
|
||||
use "^3.1.0"
|
||||
|
||||
sort-keys@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
|
||||
integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0=
|
||||
dependencies:
|
||||
is-plain-obj "^1.0.0"
|
||||
|
||||
source-list-map@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
|
||||
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
|
||||
|
||||
source-map-resolve@^0.5.0:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
|
||||
integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==
|
||||
dependencies:
|
||||
atob "^2.1.1"
|
||||
decode-uri-component "^0.2.0"
|
||||
resolve-url "^0.2.1"
|
||||
source-map-url "^0.4.0"
|
||||
urix "^0.1.0"
|
||||
|
||||
source-map-url@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
|
||||
integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
|
||||
|
||||
source-map@^0.4.2:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
|
||||
integrity sha1-66T12pwNyZneaAMti092FzZSA2s=
|
||||
dependencies:
|
||||
amdefine ">=0.0.4"
|
||||
|
||||
source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
||||
|
||||
source-map@^0.6.1, source-map@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
spdx-correct@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
|
||||
integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
|
||||
dependencies:
|
||||
spdx-expression-parse "^3.0.0"
|
||||
spdx-license-ids "^3.0.0"
|
||||
|
||||
spdx-exceptions@^2.1.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
|
||||
integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
|
||||
|
||||
spdx-expression-parse@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
|
||||
integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
|
||||
dependencies:
|
||||
spdx-exceptions "^2.1.0"
|
||||
spdx-license-ids "^3.0.0"
|
||||
|
||||
spdx-license-ids@^3.0.0:
|
||||
version "3.0.5"
|
||||
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
|
||||
integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
|
||||
|
||||
split-string@^3.0.1, split-string@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
|
||||
integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
|
||||
dependencies:
|
||||
extend-shallow "^3.0.0"
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
|
||||
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
|
||||
dependencies:
|
||||
asn1 "~0.2.3"
|
||||
assert-plus "^1.0.0"
|
||||
bcrypt-pbkdf "^1.0.0"
|
||||
dashdash "^1.12.0"
|
||||
ecc-jsbn "~0.1.1"
|
||||
getpass "^0.1.1"
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.0.2"
|
||||
tweetnacl "~0.14.0"
|
||||
|
||||
static-extend@^0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
|
||||
integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
|
||||
dependencies:
|
||||
define-property "^0.2.5"
|
||||
object-copy "^0.1.0"
|
||||
|
||||
stdout-stream@^1.4.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de"
|
||||
integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==
|
||||
dependencies:
|
||||
readable-stream "^2.0.1"
|
||||
|
||||
stream-browserify@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
|
||||
integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==
|
||||
dependencies:
|
||||
inherits "~2.0.1"
|
||||
readable-stream "^2.0.2"
|
||||
|
||||
stream-http@^2.7.2:
|
||||
version "2.8.3"
|
||||
resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
|
||||
integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==
|
||||
dependencies:
|
||||
builtin-status-codes "^3.0.0"
|
||||
inherits "^2.0.1"
|
||||
readable-stream "^2.3.6"
|
||||
to-arraybuffer "^1.0.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
strict-uri-encode@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
||||
integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
|
||||
|
||||
string-width@^1.0.1, string-width@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
|
||||
integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
|
||||
dependencies:
|
||||
code-point-at "^1.0.0"
|
||||
is-fullwidth-code-point "^1.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
|
||||
"string-width@^1.0.2 || 2":
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
|
||||
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
|
||||
dependencies:
|
||||
is-fullwidth-code-point "^2.0.0"
|
||||
strip-ansi "^4.0.0"
|
||||
|
||||
string_decoder@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
|
||||
integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
|
||||
dependencies:
|
||||
safe-buffer "~5.2.0"
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||
integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
strip-ansi@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||
integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
|
||||
strip-bom@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
|
||||
integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
|
||||
dependencies:
|
||||
is-utf8 "^0.2.0"
|
||||
|
||||
strip-indent@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
|
||||
integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
|
||||
dependencies:
|
||||
get-stdin "^4.0.1"
|
||||
|
||||
strip-json-comments@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
||||
|
||||
style-loader@^0.17.0:
|
||||
version "0.17.0"
|
||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.17.0.tgz#e8254bccdb7af74bd58274e36107b4d5ab4df310"
|
||||
integrity sha1-6CVLzNt690vVgnTjYQe01atN8xA=
|
||||
dependencies:
|
||||
loader-utils "^1.0.2"
|
||||
|
||||
supports-color@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
||||
integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
|
||||
|
||||
supports-color@^3.1.0, supports-color@^3.2.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
|
||||
integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=
|
||||
dependencies:
|
||||
has-flag "^1.0.0"
|
||||
|
||||
supports-color@^5.3.0, supports-color@^5.4.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
svgo@^0.7.0:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
|
||||
integrity sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=
|
||||
dependencies:
|
||||
coa "~1.0.1"
|
||||
colors "~1.1.2"
|
||||
csso "~2.3.1"
|
||||
js-yaml "~3.7.0"
|
||||
mkdirp "~0.5.1"
|
||||
sax "~1.2.1"
|
||||
whet.extend "~0.9.9"
|
||||
|
||||
tapable@^0.2.7, tapable@~0.2.5:
|
||||
version "0.2.9"
|
||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.9.tgz#af2d8bbc9b04f74ee17af2b4d9048f807acd18a8"
|
||||
integrity sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==
|
||||
|
||||
tar@^2.0.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40"
|
||||
integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==
|
||||
dependencies:
|
||||
block-stream "*"
|
||||
fstream "^1.0.12"
|
||||
inherits "2"
|
||||
|
||||
tar@^4:
|
||||
version "4.4.13"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525"
|
||||
integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==
|
||||
dependencies:
|
||||
chownr "^1.1.1"
|
||||
fs-minipass "^1.2.5"
|
||||
minipass "^2.8.6"
|
||||
minizlib "^1.2.1"
|
||||
mkdirp "^0.5.0"
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.3"
|
||||
|
||||
timers-browserify@^2.0.4:
|
||||
version "2.0.11"
|
||||
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f"
|
||||
integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==
|
||||
dependencies:
|
||||
setimmediate "^1.0.4"
|
||||
|
||||
to-arraybuffer@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
|
||||
integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
|
||||
|
||||
to-object-path@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
|
||||
integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
|
||||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
|
||||
to-regex-range@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
|
||||
integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
|
||||
dependencies:
|
||||
is-number "^3.0.0"
|
||||
repeat-string "^1.6.1"
|
||||
|
||||
to-regex@^3.0.1, to-regex@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
|
||||
integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
|
||||
dependencies:
|
||||
define-property "^2.0.2"
|
||||
extend-shallow "^3.0.2"
|
||||
regex-not "^1.0.2"
|
||||
safe-regex "^1.1.0"
|
||||
|
||||
tough-cookie@~2.4.3:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
|
||||
integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
|
||||
dependencies:
|
||||
psl "^1.1.24"
|
||||
punycode "^1.4.1"
|
||||
|
||||
trim-newlines@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
|
||||
integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
|
||||
|
||||
"true-case-path@^1.0.2":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"
|
||||
integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==
|
||||
dependencies:
|
||||
glob "^7.1.2"
|
||||
|
||||
tty-browserify@0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
|
||||
integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
||||
|
||||
uglify-js@^2.8.27:
|
||||
version "2.8.29"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
|
||||
integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0=
|
||||
dependencies:
|
||||
source-map "~0.5.1"
|
||||
yargs "~3.10.0"
|
||||
optionalDependencies:
|
||||
uglify-to-browserify "~1.0.0"
|
||||
|
||||
uglify-to-browserify@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
|
||||
integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc=
|
||||
|
||||
union-value@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
|
||||
integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
|
||||
dependencies:
|
||||
arr-union "^3.1.0"
|
||||
get-value "^2.0.6"
|
||||
is-extendable "^0.1.1"
|
||||
set-value "^2.0.1"
|
||||
|
||||
uniq@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
|
||||
integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
|
||||
|
||||
uniqs@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
|
||||
integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI=
|
||||
|
||||
unset-value@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
|
||||
integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
|
||||
dependencies:
|
||||
has-value "^0.3.1"
|
||||
isobject "^3.0.0"
|
||||
|
||||
upath@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
|
||||
integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
|
||||
integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
urix@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
||||
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
|
||||
|
||||
url@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
|
||||
integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=
|
||||
dependencies:
|
||||
punycode "1.3.2"
|
||||
querystring "0.2.0"
|
||||
|
||||
use@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
|
||||
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
|
||||
|
||||
util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
util@0.10.3:
|
||||
version "0.10.3"
|
||||
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
|
||||
integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk=
|
||||
dependencies:
|
||||
inherits "2.0.1"
|
||||
|
||||
util@^0.11.0:
|
||||
version "0.11.1"
|
||||
resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61"
|
||||
integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==
|
||||
dependencies:
|
||||
inherits "2.0.3"
|
||||
|
||||
uuid@^3.3.2:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
|
||||
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
|
||||
|
||||
validate-npm-package-license@^3.0.1:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
|
||||
integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
|
||||
dependencies:
|
||||
spdx-correct "^3.0.0"
|
||||
spdx-expression-parse "^3.0.0"
|
||||
|
||||
vendors@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.3.tgz#a6467781abd366217c050f8202e7e50cc9eef8c0"
|
||||
integrity sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
|
||||
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
vm-browserify@^1.0.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||
|
||||
watchpack@^1.3.1:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
|
||||
integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==
|
||||
dependencies:
|
||||
chokidar "^2.0.2"
|
||||
graceful-fs "^4.1.2"
|
||||
neo-async "^2.5.0"
|
||||
|
||||
webpack-sources@^1.0.1:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
|
||||
integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
|
||||
dependencies:
|
||||
source-list-map "^2.0.0"
|
||||
source-map "~0.6.1"
|
||||
|
||||
webpack@^2.5.1:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.7.0.tgz#b2a1226804373ffd3d03ea9c6bd525067034f6b1"
|
||||
integrity sha512-MjAA0ZqO1ba7ZQJRnoCdbM56mmFpipOPUv/vQpwwfSI42p5PVDdoiuK2AL2FwFUVgT859Jr43bFZXRg/LNsqvg==
|
||||
dependencies:
|
||||
acorn "^5.0.0"
|
||||
acorn-dynamic-import "^2.0.0"
|
||||
ajv "^4.7.0"
|
||||
ajv-keywords "^1.1.1"
|
||||
async "^2.1.2"
|
||||
enhanced-resolve "^3.3.0"
|
||||
interpret "^1.0.0"
|
||||
json-loader "^0.5.4"
|
||||
json5 "^0.5.1"
|
||||
loader-runner "^2.3.0"
|
||||
loader-utils "^0.2.16"
|
||||
memory-fs "~0.4.1"
|
||||
mkdirp "~0.5.0"
|
||||
node-libs-browser "^2.0.0"
|
||||
source-map "^0.5.3"
|
||||
supports-color "^3.1.0"
|
||||
tapable "~0.2.5"
|
||||
uglify-js "^2.8.27"
|
||||
watchpack "^1.3.1"
|
||||
webpack-sources "^1.0.1"
|
||||
yargs "^6.0.0"
|
||||
|
||||
whet.extend@~0.9.9:
|
||||
version "0.9.9"
|
||||
resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"
|
||||
integrity sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=
|
||||
|
||||
which-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
|
||||
integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
|
||||
|
||||
which@1, which@^1.2.9:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wide-align@^1.1.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
|
||||
integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
|
||||
dependencies:
|
||||
string-width "^1.0.2 || 2"
|
||||
|
||||
window-size@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
|
||||
integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=
|
||||
|
||||
wordwrap@0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
|
||||
integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
|
||||
|
||||
wrap-ansi@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
|
||||
integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
|
||||
dependencies:
|
||||
string-width "^1.0.1"
|
||||
strip-ansi "^3.0.1"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
||||
y18n@^3.2.1:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696"
|
||||
integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==
|
||||
|
||||
yallist@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
|
||||
|
||||
yallist@^3.0.0, yallist@^3.0.3:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
||||
yargs-parser@^4.2.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
|
||||
integrity sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=
|
||||
dependencies:
|
||||
camelcase "^3.0.0"
|
||||
|
||||
yargs-parser@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
|
||||
integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=
|
||||
dependencies:
|
||||
camelcase "^3.0.0"
|
||||
|
||||
yargs@^6.0.0:
|
||||
version "6.6.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
|
||||
integrity sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=
|
||||
dependencies:
|
||||
camelcase "^3.0.0"
|
||||
cliui "^3.2.0"
|
||||
decamelize "^1.1.1"
|
||||
get-caller-file "^1.0.1"
|
||||
os-locale "^1.4.0"
|
||||
read-pkg-up "^1.0.1"
|
||||
require-directory "^2.1.1"
|
||||
require-main-filename "^1.0.1"
|
||||
set-blocking "^2.0.0"
|
||||
string-width "^1.0.2"
|
||||
which-module "^1.0.0"
|
||||
y18n "^3.2.1"
|
||||
yargs-parser "^4.2.0"
|
||||
|
||||
yargs@^7.0.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
|
||||
integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=
|
||||
dependencies:
|
||||
camelcase "^3.0.0"
|
||||
cliui "^3.2.0"
|
||||
decamelize "^1.1.1"
|
||||
get-caller-file "^1.0.1"
|
||||
os-locale "^1.4.0"
|
||||
read-pkg-up "^1.0.1"
|
||||
require-directory "^2.1.1"
|
||||
require-main-filename "^1.0.1"
|
||||
set-blocking "^2.0.0"
|
||||
string-width "^1.0.2"
|
||||
which-module "^1.0.0"
|
||||
y18n "^3.2.1"
|
||||
yargs-parser "^5.0.0"
|
||||
|
||||
yargs@~3.10.0:
|
||||
version "3.10.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
|
||||
integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=
|
||||
dependencies:
|
||||
camelcase "^1.0.2"
|
||||
cliui "^2.1.0"
|
||||
decamelize "^1.0.0"
|
||||
window-size "0.1.0"
|