@innovastudio/contentbuilder 1.1.6 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -80,6 +80,8 @@ React and Vue project examples are provided in separate downloads in the user ar
80
80
  - scss/ (Only provided in Source Code package)
81
81
  - docs/
82
82
  - README.md (Documentation)
83
+ - readme.txt (Readme file)
84
+ - readme-sourcecode.txt (Readme file for Source Code package)
83
85
  - ...
84
86
 
85
87
  ## Snippets
@@ -396,8 +398,6 @@ To try a working example, please open example2.php.
396
398
 
397
399
  #### 2. Using AJAX Post Method
398
400
 
399
- Example (using axios):
400
-
401
401
  ```javascript
402
402
  builder.saveImages('', ()=>{
403
403
 
@@ -408,15 +408,21 @@ builder.saveImages('', ()=>{
408
408
 
409
409
  }, (img, base64, filename)=>{
410
410
 
411
- // Upload image process
412
- axios.post('/upload', { image: base64, filename: filename }).then((response)=>{
413
-
414
- const uploadedImageUrl = response.data.url; // get saved image url
415
-
416
- img.setAttribute('src', uploadedImageUrl); // automatically replace base64 src with image url
417
-
418
- }).catch((err)=>{
419
- console.log(err)
411
+ // Upload base64 images
412
+ const reqBody = { image: base64, filename: filename };
413
+ fetch('/uploadbase64', {
414
+ method:'POST',
415
+ body: JSON.stringify(reqBody),
416
+ headers: {
417
+ 'Content-Type': 'application/json',
418
+ }
419
+ })
420
+ .then(response=>response.json())
421
+ .then(response=>{
422
+ if(!response.error) {
423
+ const uploadedImageUrl = response.url;
424
+ img.setAttribute('src', uploadedImageUrl); // Update image src
425
+ }
420
426
  });
421
427
 
422
428
  });
@@ -427,24 +433,65 @@ In this example, each image will be sent to an endpoint: /upload
427
433
  If you're using Node.js, you can implement the endpoint to save the images using:
428
434
 
429
435
  ```javascript
436
+ const express = require('express');
437
+ const fs = require('fs');
438
+ const app = express();
439
+ const path = require('path');
440
+ const cors = require('cors');
441
+ const serveStatic = require('serve-static');
442
+ const formidable = require('formidable-serverless');
443
+ const sharp = require('sharp');
444
+
430
445
  var $path = __dirname + '/public/uploads/'; // Physical path
431
446
  var $urlpath = 'uploads/'; // URL path
432
447
 
433
- app.post('/upload', (req, res) => {
448
+ app.use(cors());
449
+ app.use(express.urlencoded({
450
+ extended: true
451
+ }));
452
+ app.use(express.json({ limit: '50mb' }));
453
+ app.use(serveStatic(path.join(__dirname, '/public')));
454
+
455
+ app.post('/uploadbase64', async (req, res) => {
434
456
  const base64Data = req.body.image;
435
457
  const filename = req.body.filename;
436
- require("fs").writeFile($path + filename, base64Data, 'base64', ()=>{
437
- res.status(200).json({
438
- success: true,
439
- url: `${$urlpath}${filename}` // return saved image url
458
+
459
+ let extension = path.extname(filename).toLowerCase();
460
+
461
+ let imageFile=base64Data;
462
+ if(extension === '.jpeg' || extension === '.jpg') {
463
+ let img = new Buffer.from(base64Data, 'base64');
464
+ imageFile = await sharp(img).resize(1600, 1600, {
465
+ fit: sharp.fit.inside,
466
+ withoutEnlargement: true,
440
467
  })
468
+ .jpeg({ quality: 70, progressive: true, force: false })
469
+ .toBuffer();
470
+ }
471
+ fs.writeFile($path + filename, imageFile, 'base64', async (err)=>{
472
+ if (err) {
473
+ res.status(500).json({
474
+ ok:true, status: 500,
475
+ error: 'Something went wrong.'
476
+ });
477
+ return
478
+ }
479
+ res.status(200).json({
480
+ ok:true, status: 200,
481
+ url: $urlpath + filename
482
+ });
441
483
  });
442
484
  });
485
+
486
+ app.listen(8081, function() {
487
+ console.log('App running on port 8081');
488
+ });
443
489
  ```
444
490
 
445
491
  Example use of the AJAX post method can be seen on:
446
492
  - React Example (react-contentbuilder folder, please see src/components/contentbuilder/buildercontrol.jsx)
447
493
  - Vue Example (vue-contentbuilder folder, please see src/components/Editable.vue)
494
+ - src/index.js (in Source Code package)
448
495
 
449
496
  ### Configuration
450
497
 
@@ -548,38 +595,41 @@ Example:
548
595
 
549
596
  ```javascript
550
597
  const builder = new ContentBuilder({
551
- container: '.container',
552
- onMediaUpload: (e)=>{
553
-
554
- const selectedFile = e.target.files[0];
555
- const filename = selectedFile.name;
556
- const reader = new FileReader();
557
- reader.onload = (e) => {
558
- let base64 = e.target.result;
559
- base64 = base64.replace(/^data:(.*?);base64,/, "");
560
- base64 = base64.replace(/ /g, '+');
561
-
562
- // Upload process using axios (https://github.com/axios/axios)
563
- axios.post('upload/', { image: base64, filename: filename }).then((response)=>{
564
-
565
- const uploadedFileUrl = response.data.url; // get saved file url
566
- builder.returnUrl(uploadedFileUrl); // return the url
567
-
568
- }).catch((err)=>{
569
- console.log(err)
570
- });
571
- }
572
- reader.readAsDataURL(selectedFile);
573
-
574
- }
575
- });
598
+ container: '.container',
599
+ onMediaUpload: (e)=>{
600
+ uploadFile(e, (response)=>{
601
+ if(!response.error) {
602
+ const uploadedImageUrl = response.url;
603
+ if(uploadedImageUrl) obj.returnUrl(uploadedImageUrl);
604
+ }
605
+ });
606
+ }
607
+ });
608
+
609
+ function uploadFile(e, callback) {
610
+
611
+ const selectedFile = e.target.files[0];
612
+
613
+ const formData = new FormData();
614
+ formData.append('file', selectedFile);
615
+ fetch('/upload', {
616
+ method: 'POST',
617
+ body: formData,
618
+ })
619
+ .then(response=>response.json())
620
+ .then(response=>{
621
+ console.log(response)
622
+ if(callback) callback(response);
623
+ });
624
+ }
576
625
  ```
577
-
578
626
  The example above uses the **returnUrl(url)** method to apply the uploaded image url back to the image dialog. You can also use the **applyLargerImage** parameter (previous version) which is the same and still works.
627
+ In the example, file will be sent to an endpoint: /upload
579
628
 
580
629
  Working examples can be seen on the React & Vue examples:
581
630
  - React Example (react-contentbuilder folder, please see src/components/contentbuilder/buildercontrol.jsx)
582
631
  - Vue Example (vue-contentbuilder folder, please see src/components/Editable.vue)
632
+ - src/index.js (in Source Code package)
583
633
 
584
634
  ## Video Upload from the Video Dialog
585
635
 
@@ -622,31 +672,34 @@ Example:
622
672
 
623
673
  ```javascript
624
674
  const builder = new ContentBuilder({
625
- container: '.container',
626
- onVideoUpload: (e)=>{
627
-
628
- const selectedFile = e.target.files[0];
629
- const filename = selectedFile.name;
630
- const reader = new FileReader();
631
- reader.onload = (e) => {
632
- let base64 = e.target.result;
633
- base64 = base64.replace(/^data:(.*?);base64,/, "");
634
- base64 = base64.replace(/ /g, '+');
635
-
636
- // Upload process using axios (https://github.com/axios/axios)
637
- axios.post('upload/', { image: base64, filename: filename }).then((response)=>{
638
-
639
- const uploadedFileUrl = response.data.url; // get saved file url
640
- builder.returnUrl(uploadedFileUrl); // return the url
641
-
642
- }).catch((err)=>{
643
- console.log(err)
644
- });
645
- }
646
- reader.readAsDataURL(selectedFile);
647
-
648
- }
649
- });
675
+ container: '.container',
676
+ ...
677
+ onVideoUpload: (e)=>{
678
+ uploadFile(e, (response)=>{
679
+ if(!response.error) {
680
+ const uploadedFileUrl = response.url;
681
+ if(uploadedFileUrl) obj.returnUrl(uploadedFileUrl);
682
+ }
683
+ });
684
+ },
685
+ });
686
+
687
+ function uploadFile(e, callback) {
688
+
689
+ const selectedFile = e.target.files[0];
690
+
691
+ const formData = new FormData();
692
+ formData.append('file', selectedFile);
693
+ fetch('/upload', {
694
+ method: 'POST',
695
+ body: formData,
696
+ })
697
+ .then(response=>response.json())
698
+ .then(response=>{
699
+ console.log(response)
700
+ if(callback) callback(response);
701
+ });
702
+ }
650
703
  ```
651
704
 
652
705
  ## Plugins
@@ -658,7 +711,6 @@ With plugins, you can extend the ContentBuilder.js features. A plugin can add an
658
711
  Plugin scripts are located in the **plugins/** folder inside **contentbuilder/**.
659
712
 
660
713
  You will see the folder containing some prebuilt plugins:
661
- - contentbuilder/plugins/buttoneditor
662
714
  - contentbuilder/plugins/helloworld
663
715
  - contentbuilder/plugins/preview
664
716
  - contentbuilder/plugins/searchreplace
@@ -675,7 +727,6 @@ const builder = new ContentBuilder({
675
727
  { name: 'preview', showInMainToolbar: true, showInElementToolbar: true },
676
728
  { name: 'wordcount', showInMainToolbar: true, showInElementToolbar: true },
677
729
  { name: 'symbols', showInMainToolbar: true, showInElementToolbar: false },
678
- { name: 'buttoneditor', showInMainToolbar: false, showInElementToolbar: false },
679
730
  ],
680
731
  pluginPath: 'contentbuilder/',
681
732
  });
@@ -703,7 +754,9 @@ As seen in the example configuration above:
703
754
  ![Button Editor Plugin](docs/plugin-symbols1.png)
704
755
  Here the Symbol button is not displayed on the element editing toolbar:
705
756
  ![Button Editor Plugin](docs/plugin-symbols2.png)
706
- - The 'buttoneditor' plugin doesn't add a button on both the main editing toolbar and the alternate editing toolbar, so the **showInMainToolbar** is set to false, and the **showInElementToolbar** is set to false. This is because the plugin is only activated when the link button is clicked. There is no button on the toolbar. Instead, an edit (pencil) icon shows on top of the button.
757
+
758
+ In the previous version, there is a ‘buttoneditor’ plugin which shows an edit (pencil) icon when a link button is clicked. This plugin is now integrated with the builder, so no configuration is needed.
759
+
707
760
  ![Button Editor Plugin](docs/plugin-buttoneditor.png)
708
761
 
709
762
  An alternative way to load the plugins is by using a configuration file:
@@ -718,7 +771,6 @@ _cb.settings.plugins = [
718
771
  { name: 'preview', showInMainToolbar: true, showInElementToolbar: true },
719
772
  { name: 'wordcount', showInMainToolbar: true, showInElementToolbar: true },
720
773
  { name: 'symbols', showInMainToolbar: true, showInElementToolbar: false },
721
- { name: 'buttoneditor', showInMainToolbar: false, showInElementToolbar: false },
722
774
  ];
723
775
  ```
724
776
 
@@ -735,7 +787,7 @@ Note that using an external configuration file is an approach that comes from th
735
787
  In the previous version, the plugins parameter is configured like this:
736
788
 
737
789
  ```javascript
738
- ['preview','wordcount', 'buttoneditor']
790
+ ['preview','wordcount']
739
791
  ```
740
792
  This still works, however we recommend using the new approach (explained above) for future flexibility.
741
793
 
@@ -1028,7 +1080,7 @@ Specify the framework classes using the **row** & **cols** parameters.
1028
1080
 
1029
1081
  Example:
1030
1082
 
1031
- Bootstrap Framework:
1083
+ Bootstrap:
1032
1084
 
1033
1085
  ```javascript
1034
1086
  const builder = new ContentBuilder({
@@ -1038,7 +1090,7 @@ const builder = new ContentBuilder({
1038
1090
  });
1039
1091
  ```
1040
1092
 
1041
- Foundation Framework:
1093
+ Foundation:
1042
1094
 
1043
1095
  ```javascript
1044
1096
  const builder = new ContentBuilder({
@@ -1048,6 +1100,27 @@ const builder = new ContentBuilder({
1048
1100
  });
1049
1101
  ```
1050
1102
 
1103
+ Tailwind:
1104
+ ```javascript
1105
+ const builder = new ContentBuilder({
1106
+ container: '.container',
1107
+ row: 'flex flex-col md:flex-row',
1108
+ cols: [
1109
+ 'w-full md:w-1/12 px-4',
1110
+ 'w-full md:w-2/12 px-4',
1111
+ 'w-full md:w-3/12 px-4',
1112
+ 'w-full md:w-4/12 px-4',
1113
+ 'w-full md:w-5/12 px-4',
1114
+ 'w-full md:w-6/12 px-4',
1115
+ 'w-full md:w-7/12 px-4',
1116
+ 'w-full md:w-8/12 px-4',
1117
+ 'w-full md:w-9/12 px-4',
1118
+ 'w-full md:w-10/12 px-4',
1119
+ 'w-full md:w-11/12 px-4',
1120
+ 'w-full px-4'],
1121
+ });
1122
+ ```
1123
+
1051
1124
  #### 2. If the framework has grid system in which the column size increment is not constant
1052
1125
 
1053
1126
  Specify two additional parameters: **colequal** & **colsizes**
@@ -1114,6 +1187,7 @@ Note:
1114
1187
  - example1-purecss.html (Pure Css Example)
1115
1188
  - example1-skeleton.html (Skeleton Example)
1116
1189
  - example1-spectre.html (Spectre.css Example)
1190
+ - example1-tailwind (Tailwind Example)
1117
1191
  - example1-uikit.html (UIKit Example)
1118
1192
  - example1-w3css.html (W3.CSS Example)
1119
1193
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@innovastudio/contentbuilder",
3
- "version": "1.1.6",
3
+ "version": "1.1.9",
4
4
  "description": "",
5
5
  "main": "public/contentbuilder/contentbuilder.esm.js",
6
6
  "files": [
@@ -2097,7 +2097,7 @@ button:focus {
2097
2097
  top: 50%;
2098
2098
  left: auto;
2099
2099
  right: 30%;
2100
- margin-top: -383px;
2100
+ margin-top: -343px;
2101
2101
  box-sizing: content-box;
2102
2102
  flex-direction: row;
2103
2103
  align-items: flex-start;
@@ -7901,37 +7901,42 @@ class Dom {
7901
7901
  this.replaceTag(area, 'i', cssClasses.fontStyle.italic);
7902
7902
  this.replaceTag(area, 'u', cssClasses.textDecoration.underline);
7903
7903
  this.replaceTag(area, 'strike', cssClasses.textDecoration.linethrough);
7904
+ this.replaceInline(area, 'font-weight', 'normal', cssClasses.fontWeight.defaultBold);
7904
7905
  this.replaceInline(area, 'font-weight', 'bold', cssClasses.fontWeight.defaultBold);
7905
- this.replaceInline(area, 'text-align', 'left', 'text-left');
7906
- this.replaceInline(area, 'text-align', 'right', 'text-right');
7907
- this.replaceInline(area, 'text-align', 'center', 'text-center');
7908
- this.replaceInline(area, 'text-align', 'justify', 'text-justify');
7909
- this.replaceInline(area, 'display', 'flex', 'flex');
7910
- this.replaceInline(area, 'justiify-content', 'flex-start', 'justify-start');
7911
- this.replaceInline(area, 'justiify-content', 'flex-end', 'justify-end');
7912
- this.replaceInline(area, 'justiify-content', 'center', 'justify-center');
7913
- this.replaceInline(area, 'justiify-content', 'space-between', 'justify-between');
7914
- this.replaceInline(area, 'align-items', 'flex-start', 'items-start');
7915
- this.replaceInline(area, 'align-items', 'flex-end', 'items-end');
7916
- this.replaceInline(area, 'align-items', 'center', 'items-center');
7917
- this.replaceInline(area, 'text-transform', 'uppercase', 'uppercase');
7918
- this.replaceInline(area, 'text-transform', 'lowercase', 'lowercase');
7919
- this.replaceInline(area, 'line-height', '1', 'leading-none');
7920
- this.replaceInline(area, 'line-height', '1.1', 'leading-11');
7921
- this.replaceInline(area, 'line-height', '1.2', 'leading-12');
7922
- this.replaceInline(area, 'line-height', '1.25', 'leading-tight');
7923
- this.replaceInline(area, 'line-height', '1.3', 'leading-13');
7924
- this.replaceInline(area, 'line-height', '1.375', 'leading-snug');
7925
- this.replaceInline(area, 'line-height', '1.4', 'leading-14');
7926
- this.replaceInline(area, 'line-height', '1.5', 'leading-15');
7927
- this.replaceInline(area, 'line-height', '1.6', 'leading-16');
7928
- this.replaceInline(area, 'line-height', '1.625', 'leading-relaxed');
7929
- this.replaceInline(area, 'line-height', '1.7', 'leading-17');
7930
- this.replaceInline(area, 'line-height', '1.8', 'leading-18');
7931
- this.replaceInline(area, 'line-height', '1.9', 'leading-19');
7932
- this.replaceInline(area, 'line-height', '2', 'leading-loose');
7933
- this.replaceInline(area, 'line-height', '2.1', 'leading-21');
7934
- this.replaceInline(area, 'line-height', '2.2', 'leading-22');
7906
+ this.replaceInline(area, 'font-weight', '600', cssClasses.fontWeight.semibold);
7907
+ this.replaceInline(area, 'text-align', 'left', cssClasses.textAlign.left);
7908
+ this.replaceInline(area, 'text-align', 'right', cssClasses.textAlign.right);
7909
+ this.replaceInline(area, 'text-align', 'center', cssClasses.textAlign.center);
7910
+ this.replaceInline(area, 'text-align', 'justify', cssClasses.textAlign.justify);
7911
+ this.replaceInline(area, 'display', 'flex', cssClasses.display.flex);
7912
+ this.replaceInline(area, 'justiify-content', 'flex-start', cssClasses.justifyContent.start);
7913
+ this.replaceInline(area, 'justiify-content', 'flex-end', cssClasses.justifyContent.end);
7914
+ this.replaceInline(area, 'justiify-content', 'center', cssClasses.justifyContent.center);
7915
+ this.replaceInline(area, 'justiify-content', 'space-between', cssClasses.justifyContent.between);
7916
+ this.replaceInline(area, 'flex-direction', 'column', cssClasses.flexDirection.column);
7917
+ this.replaceInline(area, 'flex-direction', 'row', cssClasses.flexDirection.row);
7918
+ this.replaceInline(area, 'align-items', 'flex-start', cssClasses.alignItems.start);
7919
+ this.replaceInline(area, 'align-items', 'flex-end', cssClasses.alignItems.end);
7920
+ this.replaceInline(area, 'align-items', 'center', cssClasses.alignItems.center);
7921
+ this.replaceInline(area, 'text-transform', 'uppercase', cssClasses.textTransform.uppercase);
7922
+ this.replaceInline(area, 'text-transform', 'lowercase', cssClasses.textTransform.lowercase);
7923
+ this.replaceInline(area, 'text-transform', 'none', cssClasses.textTransform.normal);
7924
+ this.replaceInline(area, 'line-height', '1', cssClasses.leading.leading_10);
7925
+ this.replaceInline(area, 'line-height', '1.1', cssClasses.leading.leading_11);
7926
+ this.replaceInline(area, 'line-height', '1.2', cssClasses.leading.leading_12);
7927
+ this.replaceInline(area, 'line-height', '1.25', cssClasses.leading.leading_125);
7928
+ this.replaceInline(area, 'line-height', '1.3', cssClasses.leading.leading_13);
7929
+ this.replaceInline(area, 'line-height', '1.375', cssClasses.leading.leading_1375);
7930
+ this.replaceInline(area, 'line-height', '1.4', cssClasses.leading.leading_14);
7931
+ this.replaceInline(area, 'line-height', '1.5', cssClasses.leading.leading_15);
7932
+ this.replaceInline(area, 'line-height', '1.6', cssClasses.leading.leading_16);
7933
+ this.replaceInline(area, 'line-height', '1.625', cssClasses.leading.leading_1625);
7934
+ this.replaceInline(area, 'line-height', '1.7', cssClasses.leading.leading_17);
7935
+ this.replaceInline(area, 'line-height', '1.8', cssClasses.leading.leading_18);
7936
+ this.replaceInline(area, 'line-height', '1.9', cssClasses.leading.leading_19);
7937
+ this.replaceInline(area, 'line-height', '2', cssClasses.leading.leading_20);
7938
+ this.replaceInline(area, 'line-height', '2.1', cssClasses.leading.leading_21);
7939
+ this.replaceInline(area, 'line-height', '2.2', cssClasses.leading.leading_22);
7935
7940
  }
7936
7941
 
7937
7942
  replaceTag(area, tag, className) {
@@ -7954,7 +7959,15 @@ class Dom {
7954
7959
  replaceInline(builder, css, value, className) {
7955
7960
  let elms = builder.querySelectorAll('*');
7956
7961
  elms.forEach(elm => {
7957
- if (elm.style[css] === `${value}`) {
7962
+ if (css === 'justiify-content') {
7963
+ /*
7964
+ For some reason, cannot use elm.style[css] for 'justify-content'
7965
+ */
7966
+ if (elm.style.justifyContent === `${value}`) {
7967
+ this.addClass(elm, className);
7968
+ elm.style.justifyContent = '';
7969
+ }
7970
+ } else if (elm.style[css] === `${value}`) {
7958
7971
  this.addClass(elm, className);
7959
7972
  elm.style[css] = '';
7960
7973
  }
@@ -46839,6 +46852,7 @@ class Image {
46839
46852
  imageTool.style.display = '';
46840
46853
  setTimeout(() => {
46841
46854
  let elm = this.builder.activeImage;
46855
+ if (!elm) return;
46842
46856
 
46843
46857
  if (dom$A.hasClass(elm.parentNode, 'img-circular')) {
46844
46858
  elm = elm.parentNode;
@@ -66258,6 +66272,34 @@ class ContentBuilder {
66258
66272
  leading_29: 'leading-29',
66259
66273
  leading_30: 'leading-30'
66260
66274
  },
66275
+ opacity: {
66276
+ opacity_0: 'opacity-0',
66277
+ opacity_2: 'opacity-2',
66278
+ opacity_4: 'opacity-4',
66279
+ opacity_5: 'opacity-5',
66280
+ opacity_6: 'opacity-6',
66281
+ opacity_8: 'opacity-8',
66282
+ opacity_10: 'opacity-10',
66283
+ opacity_12: 'opacity-12',
66284
+ opacity_15: 'opacity-15',
66285
+ opacity_20: 'opacity-20',
66286
+ opacity_25: 'opacity-25',
66287
+ opacity_30: 'opacity-30',
66288
+ opacity_35: 'opacity-35',
66289
+ opacity_40: 'opacity-40',
66290
+ opacity_45: 'opacity-45',
66291
+ opacity_50: 'opacity-50',
66292
+ opacity_55: 'opacity-55',
66293
+ opacity_60: 'opacity-60',
66294
+ opacity_65: 'opacity-65',
66295
+ opacity_70: 'opacity-70',
66296
+ opacity_75: 'opacity-75',
66297
+ opacity_80: 'opacity-80',
66298
+ opacity_85: 'opacity-85',
66299
+ opacity_90: 'opacity-90',
66300
+ opacity_95: 'opacity-95',
66301
+ opacity_100: 'opacity-100'
66302
+ },
66261
66303
  padding: {
66262
66304
  all: {
66263
66305
  p_0: 'p-0',
@@ -66673,7 +66715,8 @@ class ContentBuilder {
66673
66715
 
66674
66716
  document.addEventListener('click', this.doDocumentClick = e => {
66675
66717
  e = e || window.event;
66676
- var target = e.target || e.srcElement;
66718
+ let target = e.target || e.srcElement;
66719
+ if (!target) return;
66677
66720
  let rowClicked = dom.hasClass(target.parentNode, 'is-builder');
66678
66721
  let containerClicked = dom.hasClass(target, 'is-builder');
66679
66722
  let a = false,