1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-08 12:12:48 +01:00

Added support for basic markdown

This commit is contained in:
Hillel Coren 2015-10-01 23:02:22 +03:00
parent 5ed1c1fb0e
commit cb16e7f950
14 changed files with 347 additions and 109 deletions

View File

@ -99,6 +99,7 @@ class TokenController extends BaseController
'method' => 'POST',
'url' => 'tokens',
'title' => trans('texts.add_token'),
'feature' => 'tokens',
];
return View::make('accounts.token', $data);

View File

@ -159,7 +159,7 @@ class StartupCheck
if (Input::has('clear_cache') || !Cache::has($name)) {
if ($name == 'paymentTerms') {
$orderBy = 'num_days';
} elseif (in_array($name, ['currencies', 'sizes', 'industries', 'languages', 'countries'])) {
} elseif (in_array($name, ['currencies', 'industries', 'languages', 'countries'])) {
$orderBy = 'name';
} else {
$orderBy = 'id';

View File

@ -79,7 +79,7 @@ class PaymentService {
];
}
private function convertInputForOmnipay($input)
public function convertInputForOmnipay($input)
{
$data = [
'firstName' => $input['first_name'],

View File

@ -1,5 +1,8 @@
<?php
// https://laracasts.com/discuss/channels/general-discussion/l5-maximum-function-nesting-level-of-100-reached-aborting/
ini_set('xdebug.max_nesting_level', 256);
define('LARAVEL_START', microtime(true));
/*

View File

@ -88,10 +88,11 @@ class PaymentLibrariesSeeder extends Seeder
['name' => 'Guatemalan Quetzal', 'code' => 'GTQ', 'symbol' => 'Q', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Malaysian Ringgit', 'code' => 'MYR', 'symbol' => 'RM', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Brazilian Real', 'code' => 'BRL', 'symbol' => 'R$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Thai baht', 'code' => 'THB', 'symbol' => 'THB ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Thai Baht', 'code' => 'THB', 'symbol' => 'THB ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Nigerian Naira', 'code' => 'NGN', 'symbol' => 'NGN ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'Argentine Peso', 'code' => 'ARS', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => '.', 'decimal_separator' => ','],
['name' => 'Bangladeshi Taka', 'code' => 'BDT', 'symbol' => 'Tk', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
['name' => 'United Arab Emirates Dirham', 'code' => 'AED', 'symbol' => 'DH ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'],
];
foreach ($currencies as $currency) {
@ -143,7 +144,7 @@ class PaymentLibrariesSeeder extends Seeder
'label' => '10/Mar/2013'
],
[
'format' => 'd-M-Yk g:i a',
'format' => 'd-M-Y g:i a',
'format_moment' => 'DD-MMM-YYYY h:mm:ss a',
'label' => '10-Mar-2013'
],

View File

@ -31573,44 +31573,59 @@ function GetPdfMake(invoice, javascript, callback) {
javascript = NINJA.decodeJavascript(invoice, javascript);
function jsonCallBack(key, val) {
if ((val+'').indexOf('$firstAndLast') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.body.length) ? parseFloat(parts[1]) : 0;
};
} else if ((val+'').indexOf('$none') === 0) {
return function (i, node) {
return 0;
};
} else if ((val+'').indexOf('$notFirstAndLastColumn') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$notFirst') === 0) {
var parts = val.split(':');
return function (i, node) {
return i === 0 ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$amount') === 0) {
var parts = val.split(':');
return function (i, node) {
return parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$primaryColor') === 0) {
var parts = val.split(':');
return NINJA.primaryColor || parts[1];
} else if ((val+'').indexOf('$secondaryColor') === 0) {
var parts = val.split(':');
return NINJA.secondaryColor || parts[1];
function jsonCallBack(key, val) {
// handle custom functions
if (typeof val === 'string') {
if (val.indexOf('$firstAndLast') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.body.length) ? parseFloat(parts[1]) : 0;
};
} else if (val.indexOf('$none') === 0) {
return function (i, node) {
return 0;
};
} else if (val.indexOf('$notFirstAndLastColumn') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 0 : parseFloat(parts[1]);
};
} else if (val.indexOf('$notFirst') === 0) {
var parts = val.split(':');
return function (i, node) {
return i === 0 ? 0 : parseFloat(parts[1]);
};
} else if (val.indexOf('$amount') === 0) {
var parts = val.split(':');
return function (i, node) {
return parseFloat(parts[1]);
};
} else if (val.indexOf('$primaryColor') === 0) {
var parts = val.split(':');
return NINJA.primaryColor || parts[1];
} else if (val.indexOf('$secondaryColor') === 0) {
var parts = val.split(':');
return NINJA.secondaryColor || parts[1];
}
}
// check for markdown
if (key === 'text') {
val = NINJA.parseMarkdownText(val, true);
}
/*
if (key === 'stack') {
val = NINJA.parseMarkdownStack(val);
val = NINJA.parseMarkdownText(val, false);
}
*/
return val;
}
//console.log(javascript);
// Add ninja logo to the footer
var dd = JSON.parse(javascript, jsonCallBack);
var designId = invoice.invoice_design_id;
if (!invoice.is_pro) {
@ -31623,8 +31638,6 @@ function GetPdfMake(invoice, javascript, callback) {
}
}
//console.log(JSON.stringify(dd.footer[1].columns));
/*
var fonts = {
Roboto: {
@ -31705,7 +31718,6 @@ NINJA.decodeJavascript = function(invoice, javascript)
}
var label = invoiceLabels[field];
if (match.indexOf('UC') >= 0) {
if (!label) console.log('match: ' + field);
label = label.toUpperCase();
}
if (match.indexOf(':') >= 0) {
@ -31740,18 +31752,19 @@ NINJA.decodeJavascript = function(invoice, javascript)
return javascript;
}
NINJA.notesAndTerms = function(invoice)
{
var data = [];
if (invoice.public_notes) {
data.push({text:invoice.public_notes, style: ['notes']});
data.push({stack:[{text: invoice.public_notes, style: ['notes']}]});
data.push({text:' '});
}
if (invoice.terms) {
data.push({text:invoiceLabels.terms, style: ['termsLabel']});
data.push({text:invoice.terms, style: ['terms']});
data.push({stack:[{text: invoice.terms, style: ['terms']}]});
}
return NINJA.prepareDataList(data, 'notesAndTerms');
@ -31802,7 +31815,7 @@ NINJA.invoiceLines = function(invoice) {
var grid = [[
{text: invoiceLabels.item, style: ['tableHeader', 'itemTableHeader']},
{text: invoiceLabels.description, style: ['tableHeader', 'descriptionTableHeader']},
{text: invoiceLabels.description, style: ['tableHeader', 'descriptionTableHeader']},
{text: invoiceLabels.unit_cost, style: ['tableHeader', 'costTableHeader']}
]];
@ -31855,7 +31868,7 @@ NINJA.invoiceLines = function(invoice) {
rowStyle = (i % 2 == 0) ? 'odd' : 'even';
row.push({style:["productKey", rowStyle], text:productKey || ' '}); // product key can be blank when selecting from a datalist
row.push({style:["notes", rowStyle], text:notes || ' '});
row.push({style:["notes", rowStyle], stack:[{text:notes || ' '}]});
row.push({style:["cost", rowStyle], text:cost});
if (!hideQuantity) {
row.push({style:["quantity", rowStyle], text:qty || ' '});
@ -32055,7 +32068,7 @@ NINJA.prepareDataList = function(oldData, section) {
var newData = [];
for (var i=0; i<oldData.length; i++) {
var item = NINJA.processItem(oldData[i], section);
if (item.text) {
if (item.text || item.stack) {
newData.push(item);
}
}
@ -32069,7 +32082,7 @@ NINJA.prepareDataTable = function(oldData, section) {
var newRow = [];
for (var j=0; j<row.length; j++) {
var item = NINJA.processItem(row[j], section);
if (item.text) {
if (item.text || item.stack) {
newRow.push(item);
}
}
@ -32108,4 +32121,88 @@ NINJA.processItem = function(item, section) {
item.style = [section];
}
return item;
}
NINJA.parseMarkdownText = function(val, groupText)
{
var rules = [
['\\\*\\\*(\\\w.+?)\\\*\\\*', {'bold': true}], // **value**
['\\\*(\\\w.+?)\\\*', {'italics': true}], // *value*
['^##(.+?)$', {'style': 'subheader'}], // ## Header
['^#(.+?)$', {'style': 'header'}] // # Subheader
];
var parts = typeof val === 'string' ? [val] : val;
for (var i=0; i<rules.length; i++) {
var rule = rules[i];
var formatter = function(data) {
return $.extend(data, rule[1]);
}
parts = NINJA.parseRegExp(parts, rule[0], formatter, true);
}
return parts.length > 1 ? parts : val;
}
/*
NINJA.parseMarkdownStack = function(val)
{
if (val.length == 1) {
var item = val[0];
var line = item.hasOwnProperty('text') ? item.text : item;
if (typeof line === 'string') {
line = [line];
}
var regExp = '^\\\* (.*[\r\n|\n|\r]?)';
var formatter = function(data) {
return {"ul": [data.text]};
}
val = NINJA.parseRegExp(line, regExp, formatter, false);
}
return val;
}
*/
NINJA.parseRegExp = function(val, regExpStr, formatter, groupText)
{
var regExp = new RegExp(regExpStr, 'gm');
var parts = [];
for (var i=0; i<val.length; i++) {
var line = val[i];
parts = parts.concat(NINJA.parseRegExpLine(line, regExp, formatter, groupText));
}
return parts.length > 1 ? parts : val;
}
NINJA.parseRegExpLine = function(line, regExp, formatter, groupText)
{
var parts = [];
var lastIndex = 0;
while (match = regExp.exec(line)) {
if (match.index > lastIndex) {
parts.push(line.substring(lastIndex, match.index));
}
var data = {};
data.text = match[1];
data = formatter(data);
parts.push(data);
lastIndex = match.index + match[0].length;
}
if (parts.length) {
if (lastIndex < line.length) {
parts.push(line.substring(lastIndex));
}
return parts;
}
return line;
}

View File

@ -17,44 +17,59 @@ function GetPdfMake(invoice, javascript, callback) {
javascript = NINJA.decodeJavascript(invoice, javascript);
function jsonCallBack(key, val) {
if ((val+'').indexOf('$firstAndLast') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.body.length) ? parseFloat(parts[1]) : 0;
};
} else if ((val+'').indexOf('$none') === 0) {
return function (i, node) {
return 0;
};
} else if ((val+'').indexOf('$notFirstAndLastColumn') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$notFirst') === 0) {
var parts = val.split(':');
return function (i, node) {
return i === 0 ? 0 : parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$amount') === 0) {
var parts = val.split(':');
return function (i, node) {
return parseFloat(parts[1]);
};
} else if ((val+'').indexOf('$primaryColor') === 0) {
var parts = val.split(':');
return NINJA.primaryColor || parts[1];
} else if ((val+'').indexOf('$secondaryColor') === 0) {
var parts = val.split(':');
return NINJA.secondaryColor || parts[1];
function jsonCallBack(key, val) {
// handle custom functions
if (typeof val === 'string') {
if (val.indexOf('$firstAndLast') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.body.length) ? parseFloat(parts[1]) : 0;
};
} else if (val.indexOf('$none') === 0) {
return function (i, node) {
return 0;
};
} else if (val.indexOf('$notFirstAndLastColumn') === 0) {
var parts = val.split(':');
return function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 0 : parseFloat(parts[1]);
};
} else if (val.indexOf('$notFirst') === 0) {
var parts = val.split(':');
return function (i, node) {
return i === 0 ? 0 : parseFloat(parts[1]);
};
} else if (val.indexOf('$amount') === 0) {
var parts = val.split(':');
return function (i, node) {
return parseFloat(parts[1]);
};
} else if (val.indexOf('$primaryColor') === 0) {
var parts = val.split(':');
return NINJA.primaryColor || parts[1];
} else if (val.indexOf('$secondaryColor') === 0) {
var parts = val.split(':');
return NINJA.secondaryColor || parts[1];
}
}
// check for markdown
if (key === 'text') {
val = NINJA.parseMarkdownText(val, true);
}
/*
if (key === 'stack') {
val = NINJA.parseMarkdownStack(val);
val = NINJA.parseMarkdownText(val, false);
}
*/
return val;
}
//console.log(javascript);
// Add ninja logo to the footer
var dd = JSON.parse(javascript, jsonCallBack);
var designId = invoice.invoice_design_id;
if (!invoice.is_pro) {
@ -67,8 +82,6 @@ function GetPdfMake(invoice, javascript, callback) {
}
}
//console.log(JSON.stringify(dd.footer[1].columns));
/*
var fonts = {
Roboto: {
@ -149,7 +162,6 @@ NINJA.decodeJavascript = function(invoice, javascript)
}
var label = invoiceLabels[field];
if (match.indexOf('UC') >= 0) {
if (!label) console.log('match: ' + field);
label = label.toUpperCase();
}
if (match.indexOf(':') >= 0) {
@ -184,18 +196,19 @@ NINJA.decodeJavascript = function(invoice, javascript)
return javascript;
}
NINJA.notesAndTerms = function(invoice)
{
var data = [];
if (invoice.public_notes) {
data.push({text:invoice.public_notes, style: ['notes']});
data.push({stack:[{text: invoice.public_notes, style: ['notes']}]});
data.push({text:' '});
}
if (invoice.terms) {
data.push({text:invoiceLabels.terms, style: ['termsLabel']});
data.push({text:invoice.terms, style: ['terms']});
data.push({stack:[{text: invoice.terms, style: ['terms']}]});
}
return NINJA.prepareDataList(data, 'notesAndTerms');
@ -246,7 +259,7 @@ NINJA.invoiceLines = function(invoice) {
var grid = [[
{text: invoiceLabels.item, style: ['tableHeader', 'itemTableHeader']},
{text: invoiceLabels.description, style: ['tableHeader', 'descriptionTableHeader']},
{text: invoiceLabels.description, style: ['tableHeader', 'descriptionTableHeader']},
{text: invoiceLabels.unit_cost, style: ['tableHeader', 'costTableHeader']}
]];
@ -299,7 +312,7 @@ NINJA.invoiceLines = function(invoice) {
rowStyle = (i % 2 == 0) ? 'odd' : 'even';
row.push({style:["productKey", rowStyle], text:productKey || ' '}); // product key can be blank when selecting from a datalist
row.push({style:["notes", rowStyle], text:notes || ' '});
row.push({style:["notes", rowStyle], stack:[{text:notes || ' '}]});
row.push({style:["cost", rowStyle], text:cost});
if (!hideQuantity) {
row.push({style:["quantity", rowStyle], text:qty || ' '});
@ -499,7 +512,7 @@ NINJA.prepareDataList = function(oldData, section) {
var newData = [];
for (var i=0; i<oldData.length; i++) {
var item = NINJA.processItem(oldData[i], section);
if (item.text) {
if (item.text || item.stack) {
newData.push(item);
}
}
@ -513,7 +526,7 @@ NINJA.prepareDataTable = function(oldData, section) {
var newRow = [];
for (var j=0; j<row.length; j++) {
var item = NINJA.processItem(row[j], section);
if (item.text) {
if (item.text || item.stack) {
newRow.push(item);
}
}
@ -532,17 +545,17 @@ NINJA.prepareDataPairs = function(oldData, section) {
for (var j=0; j<row.length; j++) {
var item = NINJA.processItem(row[j], section);
if (!item.text) {
isBlank = true;
isBlank = true;
}
if (j == 1) {
NINJA.processItem(row[j], section + "Value");
}
}
}
if (!isBlank) {
newData.push(oldData[i]);
}
}
return newData;
return newData;
}
NINJA.processItem = function(item, section) {
@ -552,4 +565,88 @@ NINJA.processItem = function(item, section) {
item.style = [section];
}
return item;
}
NINJA.parseMarkdownText = function(val, groupText)
{
var rules = [
['\\\*\\\*(\\\w.+?)\\\*\\\*', {'bold': true}], // **value**
['\\\*(\\\w.+?)\\\*', {'italics': true}], // *value*
['^##(.+?)$', {'style': 'subheader'}], // ## Header
['^#(.+?)$', {'style': 'header'}] // # Subheader
];
var parts = typeof val === 'string' ? [val] : val;
for (var i=0; i<rules.length; i++) {
var rule = rules[i];
var formatter = function(data) {
return $.extend(data, rule[1]);
}
parts = NINJA.parseRegExp(parts, rule[0], formatter, true);
}
return parts.length > 1 ? parts : val;
}
/*
NINJA.parseMarkdownStack = function(val)
{
if (val.length == 1) {
var item = val[0];
var line = item.hasOwnProperty('text') ? item.text : item;
if (typeof line === 'string') {
line = [line];
}
var regExp = '^\\\* (.*[\r\n|\n|\r]?)';
var formatter = function(data) {
return {"ul": [data.text]};
}
val = NINJA.parseRegExp(line, regExp, formatter, false);
}
return val;
}
*/
NINJA.parseRegExp = function(val, regExpStr, formatter, groupText)
{
var regExp = new RegExp(regExpStr, 'gm');
var parts = [];
for (var i=0; i<val.length; i++) {
var line = val[i];
parts = parts.concat(NINJA.parseRegExpLine(line, regExp, formatter, groupText));
}
return parts.length > 1 ? parts : val;
}
NINJA.parseRegExpLine = function(line, regExp, formatter, groupText)
{
var parts = [];
var lastIndex = 0;
while (match = regExp.exec(line)) {
if (match.index > lastIndex) {
parts.push(line.substring(lastIndex, match.index));
}
var data = {};
data.text = match[1];
data = formatter(data);
parts.push(data);
lastIndex = match.index + match[0].length;
}
if (parts.length) {
if (lastIndex < line.length) {
parts.push(line.substring(lastIndex));
}
return parts;
}
return line;
}

View File

@ -108,18 +108,17 @@
</div>
</div>
@if (Auth::user()->isPro())
<center>
{!! Button::success(trans('texts.save'))->large()->submit()->appendIcon(Icon::create('floppy-disk')) !!}
</center>
@else
<script>
$(function() {
$('form.warn-on-exit input').prop('disabled', true);
});
</script>
@endif
@if (Auth::user()->isPro())
<center>
{!! Button::success(trans('texts.save'))->large()->submit()->appendIcon(Icon::create('floppy-disk')) !!}
</center>
@else
<script>
$(function() {
$('form.warn-on-exit input').prop('disabled', true);
});
</script>
@endif
<div class="modal fade" id="iframeHelpModal" tabindex="-1" role="dialog" aria-labelledby="iframeHelpModalLabel" aria-hidden="true">

View File

@ -9,8 +9,12 @@
@if (!Auth::user()->account->isPro())
<center>
<div style="font-size:larger;" class="col-md-8 col-md-offset-2">{!! trans('texts.pro_plan_advanced_settings', ['link'=>'<a href="#" onclick="showProPlan(\''.$feature.'\')">'.trans('texts.pro_plan.remove_logo_link').'</a>']) !!}</div>
&nbsp;<p/>&nbsp;
<div style="font-size:larger;" class="col-md-8 col-md-offset-2">
{!! trans('texts.pro_plan_advanced_settings', ['link'=>'<a href="#" onclick="showProPlan(\''.$feature.'\')">'.trans('texts.pro_plan.remove_logo_link').'</a>']) !!}
</div>
<p>&nbsp;<p/>
</center>
@endif

View File

@ -22,11 +22,20 @@
</div>
</div>
@if (Auth::user()->isPro())
{!! Former::actions(
Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/company/advanced_settings/token_management'))->appendIcon(Icon::create('remove-circle'))->large(),
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))
) !!}
@else
<script>
$(function() {
$('form.warn-on-exit input').prop('disabled', true);
});
</script>
@endif
{!! Former::actions(
Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/company/advanced_settings/token_management'))->appendIcon(Icon::create('remove-circle'))->large(),
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))
) !!}
{!! Former::close() !!}

View File

@ -239,6 +239,13 @@
"termsLabel": {
"bold": true,
"margin": [0, 0, 0, 4]
},
"header": {
"fontSize": "$fontSizeLargest",
"bold": true
},
"subheader": {
"fontSize": "$fontSizeLarger"
}
},
"pageMargins": [0, 80, 0, 40]

View File

@ -185,7 +185,14 @@
},
"termsLabel": {
"bold": true
}
},
"header": {
"fontSize": "$fontSizeLargest",
"bold": true
},
"subheader": {
"fontSize": "$fontSizeLarger"
}
},
"pageMargins": [40, 40, 40, 60]
}

View File

@ -230,8 +230,14 @@
},
"invoiceNumber": {
"bold": true
},
"header": {
"fontSize": "$fontSizeLargest",
"bold": true
},
"subheader": {
"fontSize": "$fontSizeLarger"
}
},
"pageMargins": [40, 80, 40, 50]
}

View File

@ -152,6 +152,13 @@
},
"balanceDue": {
"fillColor": "#e6e6e6"
},
"header": {
"fontSize": "$fontSizeLargest",
"bold": true
},
"subheader": {
"fontSize": "$fontSizeLarger"
}
},
"pageMargins": [40, 40, 40, 60]