- 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 - 41
 - 42
 - 43
 - 44
 - 45
 - 46
 - 47
 - 48
 - 49
 - 50
 - 51
 - 52
 - 53
 - 54
 - 55
 - 56
 - 57
 - 58
 - 59
 - 60
 - 61
 - 62
 - 63
 - 64
 - 65
 - 66
 - 67
 - 68
 - 69
 - 70
 - 71
 - 72
 - 73
 - 74
 - 75
 - 76
 - 77
 - 78
 - 79
 - 80
 - 81
 - 82
 - 83
 - 84
 - 85
 - 86
 - 87
 - 88
 - 89
 - 90
 - 91
 - 92
 - 93
 - 94
 - 95
 - 96
 - 97
 - 98
 - 99
 - 100
 - 101
 - 102
 - 103
 - 104
 - 105
 - 106
 - 107
 - 108
 - 109
 - 110
 - 111
 - 112
 - 113
 - 114
 - 115
 - 116
 - 117
 - 118
 - 119
 - 120
 - 121
 - 122
 - 123
 - 124
 - 125
 - 126
 - 127
 - 128
 - 129
 - 130
 - 131
 - 132
 - 133
 - 134
 - 135
 - 136
 - 137
 - 138
 - 139
 - 140
 - 141
 - 142
 - 143
 - 144
 - 145
 - 146
 - 147
 - 148
 - 149
 - 150
 - 151
 - 152
 - 153
 - 154
 - 155
 - 156
 - 157
 - 158
 - 159
 - 160
 - 161
 - 162
 - 163
 - 164
 - 165
 - 166
 - 167
 - 168
 - 169
 - 170
 - 171
 - 172
 - 173
 - 174
 - 175
 - 176
 - 177
 - 178
 - 179
 - 180
 - 181
 - 182
 - 183
 - 184
 - 185
 - 186
 - 187
 - 188
 - 189
 - 190
 - 191
 - 192
 - 193
 - 194
 - 195
 - 196
 - 197
 - 198
 - 199
 - 200
 - 201
 - 202
 - 203
 - 204
 - 205
 - 206
 - 207
 - 208
 - 209
 - 210
 - 211
 - 212
 - 213
 - 214
 - 215
 - 216
 - 217
 - 218
 - 219
 - 220
 - 221
 - 222
 - 223
 - 224
 - 225
 - 226
 - 227
 - 228
 - 229
 - 230
 - 231
 - 232
 - 233
 - 234
 - 235
 - 236
 - 237
 - 238
 - 239
 - 240
 - 241
 - 242
 - 243
 - 244
 - 245
 - 246
 - 247
 - 248
 - 249
 - 250
 - 251
 - 252
 - 253
 - 254
 - 255
 - 256
 - 257
 - 258
 - 259
 - 260
 - 261
 - 262
 - 263
 - 264
 - 265
 - 266
 - 267
 - 268
 - 269
 - 270
 - 271
 - 272
 - 273
 - 274
 - 275
 - 276
 - 277
 - 278
 - 279
 - 280
 - 281
 - 282
 - 283
 - 284
 - 285
 - 286
 - 287
 - 288
 - 289
 - 290
 - 291
 - 292
 - 293
 - 294
 - 295
 - 296
 - 297
 - 298
 - 299
 - 300
 - 301
 - 302
 - 303
 - 304
 - 305
 - 306
 - 307
 - 308
 - 309
 - 310
 - 311
 - 312
 - 313
 - 314
 - 315
 - 316
 - 317
 - 318
 - 319
 - 320
 - 321
 - 322
 - 323
 - 324
 - 325
 - 326
 - 327
 - 328
 - 329
 - 330
 - 331
 - 332
 - 333
 - 334
 - 335
 - 336
 - 337
 - 338
 - 339
 - 340
 - 341
 - 342
 - 343
 - 344
 - 345
 - 346
 - 347
 - 348
 - 349
 - 350
 - 351
 - 352
 - 353
 - 354
 - 355
 - 356
 - 357
 - 358
 - 359
 - 360
 - 361
 - 362
 - 363
 - 364
 - 365
 - 366
 - 367
 - 368
 - 369
 - 370
 - 371
 - 372
 - 373
 - 374
 - 375
 - 376
 - 377
 - 378
 - 379
 - 380
 - 381
 - 382
 - 383
 - 384
 - 385
 - 386
 - 387
 - 388
 - 389
 - 390
 - 391
 - 392
 - 393
 - 394
 - 395
 - 396
 - 397
 - 398
 - 399
 - 400
 - 401
 - 402
 - 403
 - 404
 - 405
 - 406
 - 407
 - 408
 - 409
 - 410
 - 411
 - 412
 - 413
 - 414
 - 415
 - 416
 - 417
 - 418
 - 419
 - 420
 - 421
 - 422
 - 423
 - 424
 - 425
 - 426
 - 427
 - 428
 - 429
 - 430
 - 431
 - 432
 - 433
 - 434
 - 435
 - 436
 - 437
 - 438
 - 439
 - 440
 - 441
 - 442
 - 443
 - 444
 - 445
 - 446
 - 447
 - 448
 - 449
 - 450
 - 451
 - 452
 - 453
 - 454
 - 455
 - 456
 - 457
 - 458
 - 459
 - 460
 - 461
 - 462
 - 463
 - 464
 - 465
 - 466
 - 467
 - 468
 - 469
 - 470
 - 471
 - 472
 - 473
 - 474
 - 475
 - 476
 - 477
 - 478
 - 479
 - 480
 - 481
 - 482
 - 483
 - 484
 - 485
 - 486
 - 487
 - 488
 - 489
 - 490
 - 491
 - 492
 - 493
 - 494
 - 495
 - 496
 - 497
 - 498
 - 499
 - 500
 - 501
 - 502
 - 503
 - 504
 - 505
 - 506
 - 507
 - 508
 - 509
 - 510
 - 511
 - 512
 - 513
 - 514
 - 515
 - 516
 - 517
 - 518
 - 519
 - 520
 - 521
 - 522
 - 523
 - 524
 - 525
 - 526
 - 527
 - 528
 - 529
 - 530
 - 531
 - 532
 - 533
 - 534
 - 535
 - 536
 - 537
 - 538
 - 539
 - 540
 - 541
 - 542
 - 543
 - 544
 - 545
 - 546
 - 547
 - 548
 - 549
 - 550
 - 551
 - 552
 - 553
 - 554
 - 555
 - 556
 - 557
 - 558
 - 559
 - 560
 - 561
 - 562
 - 563
 - 564
 - 565
 - 566
 - 567
 - 568
 - 569
 - 570
 - 571
 - 572
 - 573
 - 574
 - 575
 - 576
 - 577
 - 578
 - 579
 - 580
 - 581
 - 582
 - 583
 - 584
 - 585
 - 586
 - 587
 - 588
 - 589
 - 590
 - 591
 - 592
 - 593
 - 594
 - 595
 - 596
 - 597
 - 598
 - 599
 - 600
 - 601
 - 602
 - 603
 - 604
 - 605
 - 606
 - 607
 - 608
 - 609
 - 610
 - 611
 - 612
 - 613
 - 614
 - 615
 - 616
 - 617
 - 618
 - 619
 - 620
 - 621
 - 622
 - 623
 - 624
 - 625
 - 626
 - 627
 - 628
 - 629
 - 630
 - 631
 - 632
 - 633
 - 634
 - 635
 - 636
 - 637
 - 638
 - 639
 - 640
 - 641
 - 642
 - 643
 - 644
 - 645
 - 646
 - 647
 - 648
 - 649
 - 650
 - 651
 
 <template>
  <div v-if="$store.state.bars.length && name" style="position: relative">
    <div class="form-group bar-actions">
      <div class="" style="text-align: right">
        <div class="" role="group">
          <button type="button" class="btn btn">Activate</button>
          <button type="button" class="btn btn-success" @click='saveBar'>Save</button>
          <button type="button" class="btn btn-danger">Delete</button>
        </div>
      </div>
    </div>
    <div class="dashboard-card">
      <h4 class="text-center">{{ name }}</h4>
      <!-- <div class="bar-actions">
        <button type="button" class="btn btn-success">Activate</button>
        <button type="button" class="btn btn-danger">Delete</button>
      </div> -->
      <div>
        <div class="form-group">
          <label>Name <small class="text-muted"><i>(required)</i></small></label>
          <input type="text" class="form-control" v-model='name' placeholder="My E-mail bar">
          <small class="form-text text-muted">
            This is simply a name so you can identify this bar later.
          </small>
        </div>
        <div class="form-group">
          <label>Exclude pages? <small class="text-muted"><i>(optional)</i></small></label>
          <input type="email" class="form-control" placeholder="mysite.com/shop, mysite.com/contact">
          <small class="form-text text-muted" hidden>
            By default, the bar will appear on every page of
            your domain. So if your domain is <i>www.example.com</i>, the bar will appear
            when a visitor visits <i>http://example.com, www.example.com/contact</i>, etc.
            Here you may exclude the pages you do not want the bar to appear.
            For example, entering <code>wwww.example.com/shop, www.example.com/sale</code>
            below, will prevent the bar from appearing on those pages.
          </small>
        </div>
        <div :class="'alert alert-' + formResult.class" v-show="formResult.result != null">
          <div class="error" v-if="formResult.result == 'error'">
            <strong>Oh no!</strong> Could not save bar because:
            <ul style="margin: 0.3em 0 0 0">
              <li>{{ formResult.payload }}</li>
            </ul>
          </div>
          <div class="success"  v-if="formResult.result == 'success'">
            <strong>Success!</strong> Your bar has been saved.
          </div>
        </div>
        <!-- <div class="" style="text-align: right">
          <input type="submit" class="btn" value="Save">
        </div> -->
      </div>
      <!-- <div style="display:block">{{ this.$store.state.bars }}</div> -->
    </div>
    <div class="dashboard-card">
      <h2 class="text-center" style="font-weight: lighter">Preview</h2>
      <!-- <p class="text-center">This is how your bar looks. You can edit the text right here, too.</p> -->
      <div id="form-css"><!-- holds css for live preview --></div>
      <div id="preview">
        <div id="nanobar" v-html='html'></div>
      </div>
    </div>
    <div class="dashboard-card">
      <h2 class="text-center" style="font-weight: lighter">Look & Feel</h2>
      <p class="text-center">
        Customize your bar's look and feel here.
      </p>
      <div class="form-group row">
        <table class="table table-sm customize">
          <tbody>
            <tr>
              <td>Background color</td>
              <td>
                <input type="color"
                class='picker'
                data-variable='backgroundColor'
                :value='variables.css.backgroundColor' />
                </td>
            </tr>
            <!--
            <tr>
              <td>Email field background color</td>
              <td><input type="color"  class='picker' value="#ff0000" /></td>
            </tr>
            <tr>
              <td>Email field text color</td>
              <td><input type="color"  class='picker' value="#ff0000" /></td>
            </tr>
            <tr>
              <td>Email button background color</td>
              <td><input type="color"  class='picker' value="#ff0000" /></td>
            </tr>
            <tr>
              <td>Email button text color</td>
              <td><input type="color"  class='picker' value="#ff0000" /></td>
            </tr>
            <tr>
              <td>Link color</td>
              <td>
                <input type="color"
                class='picker'
                data-variable='linkColor'
                :value='cssVars.linkColor' />
              </td>
            </tr>
             -->
            <tr>
              <td>Close button color</td>
              <td>
                <input type="color"
                class='picker'
                data-variable='closeButtonColor'
                :value='variables.css.closeButtonColor' />
              </td>
            </tr>
            <tr>
              <td>Close button text</td>
              <td colspan="3">
                <input type="text" />
              </td>
            </tr>
            <tr>
              <td>Padding</td>
              <td colspan="3">
                <!-- slice -2 to remove 'px' -->
                <input type="range"
                min="0"
                max="100"
                data-variable='padding'
                :value='variables.css.padding.slice(0,-2)'
                @change="updateCss">
              </td>
            </tr>
            <tr>
              <td>Border</td>
              <td>
                <input
                type="color"
                class='picker'
                data-variable='borderColor'
                :value='variables.css.borderColor' />
              </td>
              <td>
                <!-- slice -2 to remove 'px' -->
                <input type="range"
                :value='variables.css.borderWidth.slice(0,-2)'
                min="0"
                max="10"
                data-variable='borderWidth'
                @change="updateCss">
              </td>
              <td>
                <div class="form-check form-check-inline">
                  <label class="form-check-label">
                    <input class="form-check-input" type="checkbox" value="option1"> Top
                  </label>
                </div>
                <div class="form-check form-check-inline">
                  <label class="form-check-label">
                    <input class="form-check-input" type="checkbox" value="option2"> Bottom
                  </label>
                </div>
                <div class="form-check form-check-inline">
                  <label class="form-check-label">
                    <input class="form-check-input" type="checkbox" value="option3"> Left
                  </label>
                </div>
                <div class="form-check form-check-inline">
                  <label class="form-check-label">
                    <input class="form-check-input" type="checkbox" value="option3"> Right
                  </label>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
    <div class="dashboard-card">
      <h2 class="text-center" style="font-weight: lighter">Bar's behavior</h2>
      <p class="text-center">
        Customize your bar's behavior here
      </p>
      <div class="form-group row">
        <table class="table table">
          <tr>
            <td>Entrance</td>
            <td>
              <div class="btn-group" data-toggle="buttons">
                <label class="btn btn-secondary"
                  :class="{active: variables.js.entrance == 'push'}">
                  <input
                    v-model="variables.js.entrance"
                    value="overlay"
                    type="radio"
                    name="entrance"> Slide-in
                </label>
                <label class="btn btn-secondary"
                  :class="{active: variables.js.entrance == 'overlay'}">
                  <input
                    v-model="variables.js.entrance"
                    value="push"
                    type="radio"
                    name="entrance"> Overlay
                </label>
              </div>
            </td>
          </tr>
          <tr>
            <td>Position</td>
            <td>
              <div class="btn-group" data-toggle="buttons">
                <label class="btn btn-secondary"
                  :class="{active: variables.js.position == 'top'}">
                  <input
                    v-model="variables.js.position"
                    value="top"
                    type="radio"
                    name="position"
                    data-variable='position'
                    @change="updateJs"
                    autocomplete="off">Top
                </label>
                <label class="btn  btn-secondary"
                  :class="{active: variables.js.position == 'bottom'}">
                  <input
                    v-model="variables.js.position"
                    value="bottom"
                    type="radio"
                    name="position"
                    data-variable='position'
                    @change="updateJs"
                    autocomplete="off">Bottom
                </label>
              </div>
            </td>
          </tr>
          <tr>
            <td>Delay</td>
            <td>
              <input type="text" v-model='variables.js.delay'>
            </td>
          </tr>
          <tr>
            <td>Autohide</td>
            <td>
              <input type="text" v-model='variables.js.autohide'>
            </td>
          </tr>
        </table>
      </div>
    </div>
  </div>
  <div v-else>
    loading.... {{ $store.state.bars.length }}
    <br>
    name:{{name}}
  </div>
</template>
<script>
  'use strict';
  const resultMap = {
    error: 'danger'
  }
  export default {
    name: 'Bar',
    data()
    {
      return {
        name: null,
        variables: null,
        isSubmitting: false,
        formResult: {
          result: null,
          payload: null,
          class: null
        }
      }
    },
    beforeCreate()
    {
    },
    computed: {
      /*
       * Bar's css and other variables.
       * These are also stored in the database,
       * so whenever we add/remove a variable here,
       * we must make sure to do the same in main.py.
       */
      /*cssVars()
      {
        const cssVars = JSON.parse(this.bar.config).variables.css
        return {
          padding: cssVars.padding,
          fontSize: cssVars.fontSize,
          borderWidth: cssVars.borderWidth,
          borderColor: cssVars.borderColor,
          backgroundColor: cssVars.backgroundColor,
          textColor: cssVars.textColor,
          linkColor: cssVars.linkColor,
          closeButtonColor: cssVars.closeButtonColor,
          closeButtonText: cssVars.closeButtonText
        }
      },*/
      /*barVariables: {
        get()
        {
          const variables = JSON.parse(this.bar.config).variables
          return {
            css: {
              padding: variables.css.padding,
              fontSize: variables.css.fontSize,
              borderWidth: variables.css.borderWidth,
              borderColor: variables.css.borderColor,
              backgroundColor: variables.css.backgroundColor,
              textColor: variables.css.textColor,
              linkColor: variables.css.linkColor,
              closeButtonColor: variables.css.closeButtonColor,
              closeButtonText: variables.css.closeButtonText
            },
            js: {
              entrance: variables.js.entrance,
              position: variables.js.position,
              delay: variables.js.delay,
              autohide: variables.js.autohide
            }
          }
        },
        set(v)
        {
        }
      },*/
      /*
       * Because we fetch our bar async, have it as computed
       * because when page loads and read local state, there
       * would be no value yet.
       */
     /* bar()
      {
        return this.$store.state.bars.length ? this.$store.state.bars[0] : ''
      },*/
      barName: {
        get()
        {
          return this.bar ? JSON.parse(this.bar.config).name : 'fetching name...'
        },
        set(input)
        {
          const cfg = JSON.parse(this.bar.config)
          cfg.name = input
          this.bar.config = JSON.stringify(cfg)
          this.updateStateBar()
        }
      },
      /*
       * Getter and Setter for the bar's html
       */
      html: {
        get()
        {
          return this.bar ? JSON.parse(this.bar.config).html : 'fetching html...'
        }
        /*,
        set(input)
        {
          const cfg = JSON.parse(this.bar.config)
          cfg.html.content = input
          this.bar.config = JSON.stringify(cfg)
          console.log('this bar cfg: ', this.bar.config)
          this.updateStateBar()
        }*/
      },
      /*
       * This is the css compiled with the cssVars() above.
       * Whenever those change, this will get updated,
       * and the view will update, causing the preview
       * to update too. This will also be sent to the db.
       */
      css()
      {
        return `
        <style>
         #nanobar {
            padding: ${this.variables.css.padding};
            font-size: ${this.variables.css.fontSize};
            border: ${this.variables.css.borderWidth} solid ${this.variables.css.borderColor};
            background: ${this.variables.css.backgroundColor};
            text-align: center;
            color: ${this.variables.css.textColor};
          }
          #nanobar > a {
            color: ${this.variables.css.linkColor};
          },
          #nanobar > .email {
            color: #000;
            background: #fff;
          },
          #nanobar > .button {
            background: green,
          },
          #nanobar > .clock {
          },
          #nanobar .close {
            color: ${this.variables.css.closeButtonColor};
          }
        </style>`
      }
    },
    mounted()
    {
      $().button('toggle')
    },
    updated()
    {
      console.log('updated..')
      if ( !this.name)
      {
        console.log('----> SET VARIABLES')
        const bar = this.$store.state.bars[0] //TODO grab by url id
        const config = JSON.parse(bar.config)
        console.log('variables...')
        this.variables = config.variables
        this.name = config.name
        console.log(this.variables)
      }
      else
      {
        console.log('store has no bars..')
      }
      $('#nanobar').trumbowyg({
        btns: [
          ['viewHTML'],
          ['formatting'],
          'btnGrp-semantic',
          //['superscript', 'subscript']
          ['foreColor', 'backColor'],
          ['link'],
          ['insertImage'],
          'btnGrp-justify',
          'btnGrp-lists',
          ['horizontalRule'],
          ['removeformat'],
          ['fullscreen']
        ]
      });
      const self = this
      $('#form-css').append(this.css)
      //$('#nanobar').append(content)
      $(".picker").spectrum({
        chooseText: 'Okay',
        change(color)
        {
          this.value = color.toHexString()
          const e = {target: this}
          self.updateCss(e)
        }
      });
    },
    methods: {
      /*
       * This updates the vuex bar. All bars are stored in vuex. So
       * to get this bar, we filter it out of the vuex bars array,
       * push the newly edited bar to the array (this.bar), and
       * dispatch the action to the store.
       * This is called after a UI element changes the bar.
       * ie, when css/html/behavior, or any part of the form, changes.
       * Each function that changes the bar should call this
       * to update the bar's state.
       */
      updateStateBar()
      {
        const allbars = this.$store.state.bars.filter(b => b.id != this.$route.params.id)
        allbars.push(this.bar)
        this.$store.dispatch({type: 'updateBars', barsArray: allbars})
      },
      /*
       * Actions triggered by the UI (sliders, color pickers, etc).
       * Each UI element has a data-variable=x where 'x' is one
       * of the variables in barVariables.css. We then update that
       * variable with the value of the UI element.
       */
      updateCss(e, method)
      {
        const self = this
        const barConfig = JSON.parse(self.bar.config)
        function update(variable, value)
        {
          // Some values require different handling
          switch (variable)
          {
            case 'borderWidth':
            case 'padding':
            case 'fontSize':
              value += 'px'
          }
          // Update css variable
          self.variables.css[variable] = value
          // self.css is updated when cssVar changes (computed).
          // Update our bar with new variables and compiled css
          barConfig.style = self.css
          barConfig.variables.css = self.variables.css
          self.bar.config = JSON.stringify(barConfig)
          // Update our bar in the vuex store - which will cause a rerender
          // of this component, updating the preview
          self.updateStateBar()
        }
        update(e.target.dataset.variable, e.target.value)
      },
      /*
       * Update js
       */
      updateJs(v)
      {
        console.log('v: ',v)
      },
      /*
       * Save bar on the server.
       */
      saveBar()
      {
        const self = this
        //const domains = document.getElementById('domains').value
        const req = new XMLHttpRequest()
        const formdata = new FormData()
        // Grab bar's html from Trumbowyg
        const cfg = JSON.parse(this.bar.config)
        cfg.html = $('#nanobar').trumbowyg('html')
        this.bar.config = JSON.stringify(cfg)
        console.log('this bar: ', this.bar)
        formdata.append('bar', JSON.stringify(this.bar))
        //formdata.append('domains', domains)
        req.open('POST', `/api/bar/${this.bar.id}`, true)
        req.send(formdata)
        req.onload = function()
        {
          if (req.status >= 200 && req.status < 400)
          {
            const response = JSON.parse(req.responseText)
            self.formResult = {
              result: response.result,
              payload: response.payload,
              class: response.result == 'error' ? 'danger' : response.result
            }
          }
          else
          {
            self.formResult = { result: 'error', message: 'Error on the server.' }
          }
          self.isSubmitting = false
        }
      },
      /*
       * Second save button. Saves the css and css variables, and
       * js behavior. Since our css and cssVars are already the way
       * we want, we just send the bar to the server :)
       */
      /*saveCss()
      {
      }*/
    }
  }
</script>