/storage/images
_ide_helper.php
/storage/debugbar
-.phpstorm.meta.php
\ No newline at end of file
+.phpstorm.meta.php
+yarn.lock
$this->setPageTitle('Settings');
// Get application version
- $version = false;
- if (function_exists('exec')) {
- $version = exec('git describe --always --tags ');
- }
+ $version = trim(file_get_contents(base_path('version')));
return view('settings/index', ['version' => $version]);
}
*/
function versioned_asset($file = '')
{
- // Don't require css and JS assets for testing
- if (config('app.env') === 'testing') return '';
-
- static $manifest = null;
- $manifestPath = 'build/manifest.json';
-
- if (is_null($manifest) && file_exists($manifestPath)) {
- $manifest = json_decode(file_get_contents(public_path($manifestPath)), true);
- } else if (!file_exists($manifestPath)) {
- if (config('app.env') !== 'production') {
- $path = public_path($manifestPath);
- $error = "No {$path} file found, Ensure you have built the css/js assets using gulp.";
- } else {
- $error = "No {$manifestPath} file found, Ensure you are using the release version of BookStack";
- }
- throw new \Exception($error);
+ static $version = null;
+
+ if (is_null($version)) {
+ $versionFile = base_path('version');
+ $version = trim(file_get_contents($versionFile));
}
- if (isset($manifest[$file])) {
- return baseUrl($manifest[$file]);
+ $additional = '';
+ if (config('app.env') === 'development') {
+ $additional = sha1_file(public_path($file));
}
- throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
+ $path = $file . '?version=' . urlencode($version) . $additional;
+ return baseUrl($path);
}
/**
{
$queryStringSections = [];
$queryData = array_merge($data, $overrideData);
-
+
// Change sorting direction is already sorted on current attribute
if (isset($overrideData['sort']) && $overrideData['sort'] === $data['sort']) {
$queryData['order'] = ($data['order'] === 'asc') ? 'desc' : 'asc';
} else {
$queryData['order'] = 'asc';
}
-
+
foreach ($queryData as $name => $value) {
$trimmedVal = trim($value);
if ($trimmedVal === '') continue;
if (count($queryStringSections) === 0) return $path;
return baseUrl($path . '?' . implode('&', $queryStringSections));
-}
\ No newline at end of file
+}
var elixir = require('laravel-elixir');
-// Custom extensions
-var gulp = require('gulp');
-var Task = elixir.Task;
-var fs = require('fs');
-
-elixir.extend('queryVersion', function(inputFiles) {
- new Task('queryVersion', function() {
- var manifestObject = {};
- var uidString = Date.now().toString(16).slice(4);
- for (var i = 0; i < inputFiles.length; i++) {
- var file = inputFiles[i];
- manifestObject[file] = file + '?version=' + uidString;
- }
- var fileContents = JSON.stringify(manifestObject, null, 1);
- fs.writeFileSync('public/build/manifest.json', fileContents);
- }).watch(['./public/css/*.css', './public/js/*.js']);
-});
-
-elixir(function(mix) {
- mix.sass('styles.scss')
- .sass('print-styles.scss')
- .sass('export-styles.scss')
- .browserify('global.js', 'public/js/common.js')
- .queryVersion(['css/styles.css', 'css/print-styles.css', 'js/common.js']);
+elixir(mix => {
+ mix.sass('styles.scss');
+ mix.sass('print-styles.scss');
+ mix.sass('export-styles.scss');
+ mix.browserify('global.js', './public/js/common.js');
});
{
"private": true,
- "devDependencies": {
- "gulp": "^3.9.0"
+ "scripts": {
+ "prod": "gulp --production",
+ "dev": "gulp watch"
},
- "dependencies": {
+ "devDependencies": {
"angular": "^1.5.5",
"angular-animate": "^1.5.5",
"angular-resource": "^1.5.5",
"angular-sanitize": "^1.5.5",
- "angular-ui-sortable": "^0.14.0",
- "babel-runtime": "^5.8.29",
- "bootstrap-sass": "^3.0.0",
+ "angular-ui-sortable": "^0.15.0",
"dropzone": "^4.0.1",
- "laravel-elixir": "^5.0.0",
+ "gulp": "^3.9.0",
+ "laravel-elixir": "^6.0.0-11",
+ "laravel-elixir-browserify-official": "^0.1.3",
"marked": "^0.3.5",
"moment": "^2.12.0",
"zeroclipboard": "^2.2.0"
<env name="AUTH_METHOD" value="standard"/>
<env name="DISABLE_EXTERNAL_SERVICES" value="true"/>
<env name="LDAP_VERSION" value="3"/>
+ <env name="STORAGE_TYPE" value="local"/>
<env name="GITHUB_APP_ID" value="aaaaaaaaaaaaaa"/>
<env name="GITHUB_APP_SECRET" value="aaaaaaaaaaaaaa"/>
<env name="GOOGLE_APP_ID" value="aaaaaaaaaaaaaa"/>
+++ /dev/null
-*
-!.gitignore
[](https://github.com/ssddanbrown/BookStack/releases/latest)
[](https://github.com/ssddanbrown/BookStack/blob/master/LICENSE)
-[](https://travis-ci.org/ssddanbrown/BookStack)
+[](https://travis-ci.org/BookStackApp/BookStack)
A platform for storing and organising information and documentation. General information and documentation for BookStack can be found at https://www.bookstackapp.com/.
* [Installation Instructions](https://www.bookstackapp.com/docs/admin/installation)
* [Documentation](https://www.bookstackapp.com/docs)
-* [Demo Instance](https://demo.bookstackapp.com) *(Login username: `
[email protected]`. Password: `password`)*
+* [Demo Instance](https://demo.bookstackapp.com)
+ * *Password: `password`*
* [BookStack Blog](https://www.bookstackapp.com/blog)
## Development & Testing
php artisan db:seed --class=DummyContentSeeder --database=mysql_testing
```
-Once done you can run `phpunit` (or `./vendor/bin/phpunit` if `phpunit` is not found) in the application root directory to run all tests.
+Once done you can run `phpunit` in the application root directory to run all tests.
## License
* [TinyColorPicker](http://www.dematte.at/tinyColorPicker/index.html)
* [Marked](https://github.com/chjj/marked)
* [Moment.js](http://momentjs.com/)
+
+Additionally, Thank you [BrowserStack](https://www.browserstack.com/) for supporting us and making cross-browser testing easy.
+++ /dev/null
-<div class="dropzone-container">
- <div class="dz-message">Drop files or click here to upload</div>
-</div>
\ No newline at end of file
+++ /dev/null
-
-<div class="image-picker">
- <div>
- <img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
- <img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
- </div>
- <button class="button" type="button" ng-click="showImageManager()">Select Image</button>
- <br>
-
- <button class="text-button" ng-click="reset()" type="button">Reset</button>
- <span ng-show="showRemove" class="sep">|</span>
- <button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
-
- <input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
-</div>
\ No newline at end of file
+++ /dev/null
-<div class="toggle-switch" ng-click="switch()" ng-class="{'active': isActive}">
- <input type="hidden" ng-attr-name="{{name}}" ng-attr-value="{{value}}"/>
- <div class="switch-handle"></div>
-</div>
\ No newline at end of file
"use strict";
-const moment = require('moment');
+import moment from 'moment';
+import 'moment/locale/en-gb';
+moment.locale('en-gb');
module.exports = function (ngApp, events) {
$scope.imageDeleteSuccess = false;
$scope.uploadedTo = $attrs.uploadedTo;
$scope.view = 'all';
-
+
$scope.searching = false;
$scope.searchTerm = '';
$scope.hasMore = preSearchHasMore;
}
$scope.cancelSearch = cancelSearch;
-
+
/**
* Runs on image upload, Adds an image to local list of images
const pageId = Number($attrs.pageId);
$scope.tags = [];
-
+
$scope.sortOptions = {
handle: '.handle',
items: '> tr',
}]);
};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
const DropZone = require('dropzone');
const markdown = require('marked');
-const toggleSwitchTemplate = require('./components/toggle-switch.html');
-const imagePickerTemplate = require('./components/image-picker.html');
-const dropZoneTemplate = require('./components/drop-zone.html');
-
module.exports = function (ngApp, events) {
/**
ngApp.directive('toggleSwitch', function () {
return {
restrict: 'A',
- template: toggleSwitchTemplate,
+ template: `
+ <div class="toggle-switch" ng-click="switch()" ng-class="{'active': isActive}">
+ <input type="hidden" ng-attr-name="{{name}}" ng-attr-value="{{value}}"/>
+ <div class="switch-handle"></div>
+ </div>
+ `,
scope: true,
link: function (scope, element, attrs) {
scope.name = attrs.name;
});
element.find('button[type="submit"]').click(submitEvent);
-
+
function submitEvent(e) {
e.preventDefault()
if (attrs.subForm) scope.$eval(attrs.subForm);
ngApp.directive('imagePicker', ['$http', 'imageManagerService', function ($http, imageManagerService) {
return {
restrict: 'E',
- template: imagePickerTemplate,
+ template: `
+ <div class="image-picker">
+ <div>
+ <img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
+ <img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
+ </div>
+ <button class="button" type="button" ng-click="showImageManager()">Select Image</button>
+ <br>
+
+ <button class="text-button" ng-click="reset()" type="button">Reset</button>
+ <span ng-show="showRemove" class="sep">|</span>
+ <button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
+
+ <input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
+ </div>
+ `,
scope: {
name: '@',
resizeHeight: '@',
ngApp.directive('dropZone', [function () {
return {
restrict: 'E',
- template: dropZoneTemplate,
+ template: `
+ <div class="dropzone-container">
+ <div class="dz-message">Drop files or click here to upload</div>
+ </div>
+ `,
scope: {
uploadUrl: '@',
eventSuccess: '=',
let val = $input.val();
let url = $input.attr('autosuggest');
let type = $input.attr('autosuggest-type');
-
+
// Add name param to request if for a value
if (type.toLowerCase() === 'value') {
let $nameInput = $input.closest('tr').find('[autosuggest-type="name"]').first();
};
}]);
};
-
-
-
-
-
-
-
-
-
-
-
-
-
-