MDL-69166 core_payment: send a purchase description to payment gateways

We truncate description to 127 chars as per PayPal requirement
This commit is contained in:
Shamim Rezaie 2020-01-06 19:54:31 +11:00
parent 7f988ff518
commit 03f20edbd5
7 changed files with 31 additions and 23 deletions

View File

@ -1,2 +1,2 @@
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("core_payment/gateways_modal",["exports","core/modal_factory","core/templates","core/str","core_payment/repository","./selectors","core/modal_events","core/toast"],function(a,b,c,d,e,f,g,h){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerEventListeners=void 0;b=k(b);c=k(c);f=k(f);g=j(g);var r="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function i(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;i=function(){return a};return a}function j(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=i();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function k(a){return a&&a.__esModule?a:{default:a}}function l(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function m(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){l(h,d,e,f,g,"next",a)}function g(a){l(h,d,e,f,g,"throw",a)}f(void 0)})}}function n(a){if("undefined"==typeof Symbol||null==a[Symbol.iterator]){if(Array.isArray(a)||(a=p(a))){var b=0,c=function(){};return{s:c,n:function n(){if(b>=a.length)return{done:!0};return{done:!1,value:a[b++]}},e:function e(a){throw a},f:c}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var d,e=!0,f=!1,g;return{s:function s(){d=a[Symbol.iterator]()},n:function n(){var a=d.next();e=a.done;return a},e:function e(a){f=!0;g=a},f:function f(){try{if(!e&&null!=d.return)d.return()}finally{if(f)throw g}}}}function p(a,b){if(!a)return;if("string"==typeof a)return q(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return q(a,b)}function q(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c<b;c++){d[c]=a[c]}return d}a.registerEventListeners=function registerEventListeners(a){var b=document.querySelector(a);b.addEventListener("click",function(a){a.preventDefault();s(b,{focusOnClose:a.target})})};var s=function(a){var i=1<arguments.length&&arguments[1]!==void 0?arguments[1]:{},j=i.focusOnClose,k=void 0===j?null:j;c.default.render("core_payment/gateways_modal",{}).done(function(i){b.default.create({type:b.default.types.SAVE_CANCEL,title:(0,d.get_string)("selectpaymenttype","core_payment"),body:i}).done(function(b){(0,h.addToastRegion)(b.getRoot()[0]);var i=a.dataset.currency;(0,e.getGatewaysSupportingCurrency)(i).done(function(a){var d={gateways:[]},e=n(a),g;try{for(e.s();!(g=e.n()).done;){var h=g.value;d.gateways.push(h)}}catch(a){e.e(a)}finally{e.f()}c.default.render("core_payment/gateways",d).done(function(a,d){c.default.replaceNodeContents(b.getRoot().find(f.default.regions.gatewaysContainer),a,d)})});b.getRoot().on(g.hidden,function(){b.destroy();try{k.focus()}catch(a){}});b.getRoot().on(g.save,function(c){var e=b.getRoot()[0],g=(e.querySelector(f.default.values.gateway)||{value:""}).value;if(g){t(e,g,a.dataset.amount,a.dataset.currency,a.dataset.component,a.dataset.componentid)}else{(0,d.get_string)("nogatewayselected","core_payment").then(function(a){return(0,h.add)(a)})}c.preventDefault()});b.show()})})},t=function(){var a=m(regeneratorRuntime.mark(function a(b,c,d,e,f,g){var h;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return"function"==typeof r.define&&r.define.amd?new Promise(function(a,b){r.require(["pg_".concat(c,"/gateways_modal")],a,b)}):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&r.require&&"component"===r.require.loader?Promise.resolve(require(("pg_".concat(c,"/gateways_modal")))):Promise.resolve(r["pg_".concat(c,"/gateways_modal")]);case 2:h=a.sent;h.process(b,d,e,f,g);case 4:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}()});
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("core_payment/gateways_modal",["exports","core/modal_factory","core/templates","core/str","core_payment/repository","./selectors","core/modal_events","core/toast"],function(a,b,c,d,e,f,g,h){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerEventListeners=void 0;b=k(b);c=k(c);f=k(f);g=j(g);var r="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function i(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;i=function(){return a};return a}function j(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=i();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function k(a){return a&&a.__esModule?a:{default:a}}function l(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function m(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){l(h,d,e,f,g,"next",a)}function g(a){l(h,d,e,f,g,"throw",a)}f(void 0)})}}function n(a){if("undefined"==typeof Symbol||null==a[Symbol.iterator]){if(Array.isArray(a)||(a=p(a))){var b=0,c=function(){};return{s:c,n:function n(){if(b>=a.length)return{done:!0};return{done:!1,value:a[b++]}},e:function e(a){throw a},f:c}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var d,e=!0,f=!1,g;return{s:function s(){d=a[Symbol.iterator]()},n:function n(){var a=d.next();e=a.done;return a},e:function e(a){f=!0;g=a},f:function f(){try{if(!e&&null!=d.return)d.return()}finally{if(f)throw g}}}}function p(a,b){if(!a)return;if("string"==typeof a)return q(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return q(a,b)}function q(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c<b;c++){d[c]=a[c]}return d}a.registerEventListeners=function registerEventListeners(a){var b=document.querySelector(a);b.addEventListener("click",function(a){a.preventDefault();s(b,{focusOnClose:a.target})})};var s=function(a){var i=1<arguments.length&&arguments[1]!==void 0?arguments[1]:{},j=i.focusOnClose,k=void 0===j?null:j;c.default.render("core_payment/gateways_modal",{}).done(function(i){b.default.create({type:b.default.types.SAVE_CANCEL,title:(0,d.get_string)("selectpaymenttype","core_payment"),body:i}).done(function(b){(0,h.addToastRegion)(b.getRoot()[0]);var i=a.dataset.currency;(0,e.getGatewaysSupportingCurrency)(i).done(function(a){var d={gateways:[]},e=n(a),g;try{for(e.s();!(g=e.n()).done;){var h=g.value;d.gateways.push(h)}}catch(a){e.e(a)}finally{e.f()}c.default.render("core_payment/gateways",d).done(function(a,d){c.default.replaceNodeContents(b.getRoot().find(f.default.regions.gatewaysContainer),a,d)})});b.getRoot().on(g.hidden,function(){b.destroy();try{k.focus()}catch(a){}});b.getRoot().on(g.save,function(c){var e=b.getRoot()[0],g=(e.querySelector(f.default.values.gateway)||{value:""}).value;if(g){t(e,g,a.dataset.amount,a.dataset.currency,a.dataset.component,a.dataset.componentid,a.dataset.description)}else{(0,d.get_string)("nogatewayselected","core_payment").then(function(a){return(0,h.add)(a)})}c.preventDefault()});b.show()})})},t=function(){var a=m(regeneratorRuntime.mark(function a(b,c,d,e,f,g,h){var i;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return"function"==typeof r.define&&r.define.amd?new Promise(function(a,b){r.require(["pg_".concat(c,"/gateways_modal")],a,b)}):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&r.require&&"component"===r.require.loader?Promise.resolve(require(("pg_".concat(c,"/gateways_modal")))):Promise.resolve(r["pg_".concat(c,"/gateways_modal")]);case 2:i=a.sent;i.process(b,d,e,f,g,h);case 4:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}()});
//# sourceMappingURL=gateways_modal.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -95,20 +95,21 @@ const show = (rootNode, {
const root = modal.getRoot()[0];
const gateway = (root.querySelector(Selectors.values.gateway) || {value: ''}).value;
if (gateway) {
processPayment(
root,
gateway,
rootNode.dataset.amount,
rootNode.dataset.currency,
rootNode.dataset.component,
rootNode.dataset.componentid
);
} else {
getString('nogatewayselected', 'core_payment').then(message => {
return addToast(message);
});
}
if (gateway) {
processPayment(
root,
gateway,
rootNode.dataset.amount,
rootNode.dataset.currency,
rootNode.dataset.component,
rootNode.dataset.componentid,
rootNode.dataset.description,
);
} else {
getString('nogatewayselected', 'core_payment').then(message => {
return addToast(message);
});
}
e.preventDefault();
});
@ -127,10 +128,11 @@ const show = (rootNode, {
* @param {string} currency The currency in the three-character ISO-4217 format
* @param {string} component Name of the component that the componentid belongs to
* @param {number} componentid An internal identifier that is used by the component
* @param {string} description Description of the payment
* @returns {Promise<void>}
*/
const processPayment = async(rootElement, gateway, amount, currency, component, componentid) => {
const processPayment = async(rootElement, gateway, amount, currency, component, componentid, description) => {
const paymentMethod = await import(`pg_${gateway}/gateways_modal`);
paymentMethod.process(rootElement, amount, currency, component, componentid);
paymentMethod.process(rootElement, amount, currency, component, componentid, description);
};

View File

@ -96,9 +96,13 @@ class helper {
*
* @param float $amount Amount of payment
* @param string $currency Currency of payment
* @param string $component Name of the component that the componentid belongs to
* @param int $componentid An internal identifier that is used by the component
* @param string $description Description of the payment
* @return array
*/
public static function gateways_modal_link_params(float $amount, string $currency, string $component, int $componentid): array {
public static function gateways_modal_link_params(float $amount, string $currency, string $component, int $componentid,
string $description): array {
return [
'id' => 'gateways-modal-trigger',
'role' => 'button',
@ -106,6 +110,7 @@ class helper {
'data-currency' => $currency,
'data-component' => $component,
'data-componentid' => $componentid,
'data-description' => $description,
];
}
}

View File

@ -1,2 +1,2 @@
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("pg_paypal/gateways_modal",["exports","./repository","core/templates","./selectors","core/truncate"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.process=void 0;b=h(b);c=f(c);d=f(d);e=f(e);function f(a){return a&&a.__esModule?a:{default:a}}function g(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;g=function(){return a};return a}function h(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=g();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function i(a,b){return n(a)||m(a,b)||k(a,b)||j()}function j(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function k(a,b){if(!a)return;if("string"==typeof a)return l(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return l(a,b)}function l(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c<b;c++){d[c]=a[c]}return d}function m(a,b){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(a)))return;var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function n(a){if(Array.isArray(a))return a}function o(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function p(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){o(h,d,e,f,g,"next",a)}function g(a){o(h,d,e,f,g,"throw",a)}f(void 0)})}}var q=function(){var a=p(regeneratorRuntime.mark(function a(b){var e,f,g;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return c.default.renderForPromise("pg_paypal/paypal_button_placeholder",{});case 2:e=a.sent;f=e.html;g=e.js;c.default.replaceNodeContents(b.querySelector(d.default.regions.gatewaysContainer),f,g);case 6:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),r=function(){var a=p(regeneratorRuntime.mark(function a(c,f,g){var h,j,k,l;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return Promise.all([q(c),b.getConfigForJs()]);case 2:h=a.sent;j=i(h,2);k=j[1];l="https://www.paypal.com/sdk/js?client-id=".concat(k.clientid,"&currency=").concat(g);s(l,function(){c.querySelector(d.default.buttons.save).style.display="none";c.querySelector(d.default.regions.gatewaysContainer).innerHTML="";paypal.Buttons({createOrder:function createOrder(a,b){return b.order.create({purchase_units:[{amount:{currency_code:g,value:f}}],application_context:{shipping_preference:"NO_SHIPPING",brand_name:e.default.truncate(k.brandname,{length:127,stripTags:!0})}})}}).render(d.default.regions.gatewaysContainer)});case 7:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.process=r;var s=function(a,b){if(s.currentlyloaded.includes(a)){b();return}var c=document.createElement("script");if(c.readyState){c.onreadystatechange=function(){if("complete"==this.readyState||"loaded"==this.readyState){this.onreadystatechange=null;b()}}}else{c.onload=function(){b()}}c.setAttribute("src",a);document.head.appendChild(c);s.currentlyloaded.push(a)};s.currentlyloaded=[]});
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("pg_paypal/gateways_modal",["exports","./repository","core/templates","./selectors","core/truncate"],function(a,b,c,d,e){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.process=void 0;b=h(b);c=f(c);d=f(d);e=f(e);function f(a){return a&&a.__esModule?a:{default:a}}function g(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;g=function(){return a};return a}function h(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=g();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function i(a,b){return n(a)||m(a,b)||k(a,b)||j()}function j(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function k(a,b){if(!a)return;if("string"==typeof a)return l(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return l(a,b)}function l(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c<b;c++){d[c]=a[c]}return d}function m(a,b){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(a)))return;var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function n(a){if(Array.isArray(a))return a}function o(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function p(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){o(h,d,e,f,g,"next",a)}function g(a){o(h,d,e,f,g,"throw",a)}f(void 0)})}}var q=function(){var a=p(regeneratorRuntime.mark(function a(b){var e,f,g;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return c.default.renderForPromise("pg_paypal/paypal_button_placeholder",{});case 2:e=a.sent;f=e.html;g=e.js;c.default.replaceNodeContents(b.querySelector(d.default.regions.gatewaysContainer),f,g);case 6:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),r=function(){var a=p(regeneratorRuntime.mark(function a(c,f,g,h,j,k){var l,m,n,o;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return Promise.all([q(c),b.getConfigForJs()]);case 2:l=a.sent;m=i(l,2);n=m[1];o="https://www.paypal.com/sdk/js?client-id=".concat(n.clientid,"&currency=").concat(g);s(o,function(){c.querySelector(d.default.buttons.save).style.display="none";c.querySelector(d.default.regions.gatewaysContainer).innerHTML="";paypal.Buttons({createOrder:function createOrder(a,b){return b.order.create({purchase_units:[{amount:{currency_code:g,value:f},description:e.default.truncate(k,{length:127,stripTags:!0})}],application_context:{shipping_preference:"NO_SHIPPING",brand_name:e.default.truncate(n.brandname,{length:127,stripTags:!0})}})}}).render(d.default.regions.gatewaysContainer)});case 7:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.process=r;var s=function(a,b){if(s.currentlyloaded.includes(a)){b();return}var c=document.createElement("script");if(c.readyState){c.onreadystatechange=function(){if("complete"==this.readyState||"loaded"==this.readyState){this.onreadystatechange=null;b()}}}else{c.onload=function(){b()}}c.setAttribute("src",a);document.head.appendChild(c);s.currentlyloaded.push(a)};s.currentlyloaded=[]});
//# sourceMappingURL=gateways_modal.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -37,7 +37,7 @@ const showPlaceholder = async(rootElement) => {
Templates.replaceNodeContents(rootElement.querySelector(Selectors.regions.gatewaysContainer), html, js);
};
export const process = async(rootElement, amount, currency, component, componentid) => {
export const process = async(rootElement, amount, currency, component, componentid, description) => {
const [
,
@ -60,7 +60,8 @@ export const process = async(rootElement, amount, currency, component, component
amount: {
currency_code: currency, // eslint-disable-line
value: amount
}
},
description: Truncate.truncate(description, {length: 127, stripTags: true}),
}],
application_context: { // eslint-disable-line
shipping_preference: 'NO_SHIPPING', // eslint-disable-line