Jelajahi Sumber

Merge branch 'GeekJosh-master'

Adam Shaw 8 tahun lalu
induk
melakukan
f404847246

+ 8 - 0
demos/js/theme-chooser.js

@@ -70,6 +70,14 @@ function initThemeChooser(settings) {
         return 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css';
       }
     }
+    else if (themeSystem === 'bootstrap4') {
+      if (themeName) {
+        return 'https://bootswatch.com/4/' + themeName + '/bootstrap.min.css';
+      }
+      else { // the default bootstrap4 theme
+        return 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';
+      }
+    }
   }
 
 

+ 32 - 1
demos/themes.html

@@ -2,6 +2,7 @@
 <html>
 <head>
 <meta charset='utf-8' />
+<link href='https://use.fontawesome.com/releases/v5.0.6/css/all.css' rel='stylesheet'>
 <link href='../dist/fullcalendar.css' rel='stylesheet' />
 <link href='../dist/fullcalendar.print.css' rel='stylesheet' media='print' />
 <script src='../node_modules/moment/moment.js'></script>
@@ -148,7 +149,8 @@
         Theme System:
 
         <select>
-          <option value='bootstrap3' selected>Bootstrap 3</option>
+          <option value='bootstrap4' selected>Bootstrap 4</option>
+          <option value='bootstrap3'>Bootstrap 3</option>
           <option value='jquery-ui'>jQuery UI</option>
           <option value='standard'>unthemed</option>
         </select>
@@ -178,6 +180,35 @@
         </select>
       </div>
 
+      <div data-theme-system="bootstrap4" class='selector' style='display:none'>
+        Theme Name:
+
+        <select>
+          <option value='' selected>Default</option>
+          <option value='cerulean'>Cerulean</option>
+          <option value='cosmo'>Cosmo</option>
+          <option value='cyborg'>Cyborg</option>
+          <option value='darkly'>Darkly</option>
+          <option value='flatly'>Flatly</option>
+          <option value='journal'>Journal</option>
+          <option value='litera'>Litera</option>
+          <option value='lumen'>Lumen</option>
+          <option value='lux'>Lux</option>
+          <option value='materia'>Materia</option>
+          <option value='minty'>Minty</option>
+          <option value='pulse'>Pulse</option>
+          <option value='sandstone'>Sandstone</option>
+          <option value='simplex'>Simplex</option>
+          <option value='sketchy'>Sketchy</option>
+          <option value='slate'>Slate</option>
+          <option value='solar'>Solar</option>
+          <option value='spacelab'>Spacelab</option>
+          <option value='superhero'>Superhero</option>
+          <option value='united'>United</option>
+          <option value='yeti'>Yeti</option>
+        </select>
+      </div>
+
       <div data-theme-system="jquery-ui" class='selector' style='display:none'>
         Theme Name:
 

+ 1 - 1
src/common/common.bootstrap3.scss

@@ -20,7 +20,7 @@
 --------------------------------------------------------------------------------------------------*/
 
 .fc-bootstrap3 .fc-popover .panel-body {
-  padding: 0; /* undo built-in padding */
+  padding: 0; // undo built-in padding
 }
 
 

+ 42 - 0
src/common/common.bootstrap4.scss

@@ -0,0 +1,42 @@
+
+.fc.fc-bootstrap4 a {
+  text-decoration: none;
+}
+
+.fc.fc-bootstrap4 a[data-goto]:hover {
+  text-decoration: underline;
+}
+
+.fc-bootstrap4 hr.fc-divider {
+  border-color: inherit;
+}
+
+.fc-bootstrap4 .fc-today.alert {
+  border-radius: 0;
+}
+
+.fc-bootstrap4 a.fc-event:not([href]):not([tabindex]) {
+  // bootstrap has a rule that sets these links to color:inherit. override.
+  color: #fff;
+}
+
+.fc-bootstrap4 .fc-popover.card {
+  position: absolute; // because .card sets it to position:relative
+}
+
+
+/* Popover
+--------------------------------------------------------------------------------------------------*/
+
+.fc-bootstrap4 .fc-popover .card-body {
+  padding: 0; // undo built-in padding
+}
+
+
+/* TimeGrid Slats (lines that run horizontally)
+--------------------------------------------------------------------------------------------------*/
+
+.fc-bootstrap4 .fc-time-grid .fc-slats table {
+  /* some themes have background color. see through to slats */
+  background: none;
+}

+ 4 - 1
src/list/ListView.ts

@@ -193,7 +193,10 @@ export default class ListView extends View {
     let altFormat = this.opt('listDayAltFormat')
 
     return '<tr class="fc-list-heading" data-date="' + dayDate.format('YYYY-MM-DD') + '">' +
-      '<td class="' + this.calendar.theme.getClass('widgetHeader') + '" colspan="3">' +
+      '<td class="' + (
+        this.calendar.theme.getClass('tableListHeading') ||
+        this.calendar.theme.getClass('widgetHeader')
+      ) + '" colspan="3">' +
         (mainFormat ?
           this.buildGotoAnchorHtml(
             dayDate,

+ 1 - 0
src/main.scss

@@ -3,6 +3,7 @@
 @import './common/common.standard.scss';
 @import './common/common.jquery-ui.scss';
 @import './common/common.bootstrap3.scss';
+@import './common/common.bootstrap4.scss';
 @import './toolbar.scss';
 @import './view.scss';
 @import './basic/basic.scss';

+ 45 - 0
src/theme/Bootstrap3Theme.ts

@@ -0,0 +1,45 @@
+import Theme from './Theme'
+
+export default class Bootstrap3Theme extends Theme {
+}
+
+Bootstrap3Theme.prototype.classes = {
+  widget: 'fc-bootstrap3',
+
+  tableGrid: 'table-bordered', // avoid `table` class b/c don't want margins. only border color
+  tableList: 'table', // `table` class creates bottom margin but who cares
+  tableListHeading: 'active',
+
+  buttonGroup: 'btn-group',
+  button: 'btn btn-default',
+  stateActive: 'active',
+  stateDisabled: 'disabled',
+
+  today: 'alert alert-info', // the plain `info` class requires `.table`, too much to ask
+
+  popover: 'panel panel-default',
+  popoverHeader: 'panel-heading',
+  popoverContent: 'panel-body',
+
+  // day grid
+  // for left/right border color when border is inset from edges (all-day in agenda view)
+  // avoid `panel` class b/c don't want margins/radius. only border color.
+  headerRow: 'panel-default',
+  dayRow: 'panel-default',
+
+  // list view
+  listView: 'panel panel-default'
+}
+
+Bootstrap3Theme.prototype.baseIconClass = 'glyphicon'
+Bootstrap3Theme.prototype.iconClasses = {
+  close: 'glyphicon-remove',
+  prev: 'glyphicon-chevron-left',
+  next: 'glyphicon-chevron-right',
+  prevYear: 'glyphicon-backward',
+  nextYear: 'glyphicon-forward'
+}
+
+Bootstrap3Theme.prototype.iconOverrideOption = 'bootstrapGlyphicons'
+Bootstrap3Theme.prototype.iconOverrideCustomButtonOption = 'bootstrapGlyphicon'
+Bootstrap3Theme.prototype.iconOverridePrefix = 'glyphicon-'

+ 45 - 0
src/theme/Bootstrap4Theme.ts

@@ -0,0 +1,45 @@
+import Theme from './Theme'
+
+export default class Bootstrap4Theme extends Theme {
+}
+
+Bootstrap4Theme.prototype.classes = {
+  widget: 'fc-bootstrap4',
+
+  tableGrid: 'table-bordered', // avoid `table` class b/c don't want margins. only border color
+  tableList: 'table', // `table` class creates bottom margin but who cares
+  tableListHeading: 'table-active',
+
+  buttonGroup: 'btn-group',
+  button: 'btn btn-primary',
+  stateActive: 'active',
+  stateDisabled: 'disabled',
+
+  today: 'alert alert-info', // the plain `info` class requires `.table`, too much to ask
+
+  popover: 'card card-primary',
+  popoverHeader: 'card-header',
+  popoverContent: 'card-body',
+
+  // day grid
+  // for left/right border color when border is inset from edges (all-day in agenda view)
+  // avoid `table` class b/c don't want margins/padding/structure. only border color.
+  headerRow: 'table-bordered',
+  dayRow: 'table-bordered',
+
+  // list view
+  listView: 'card card-primary'
+}
+
+Bootstrap4Theme.prototype.baseIconClass = 'fa'
+Bootstrap4Theme.prototype.iconClasses = {
+  close: 'fa-times',
+  prev: 'fa-chevron-left',
+  next: 'fa-chevron-right',
+  prevYear: 'fa-angle-double-left',
+  nextYear: 'fa-angle-double-right'
+}
+
+Bootstrap4Theme.prototype.iconOverrideOption = 'bootstrapFontAwesome'
+Bootstrap4Theme.prototype.iconOverrideCustomButtonOption = 'bootstrapFontAwesome'
+Bootstrap4Theme.prototype.iconOverridePrefix = 'fa-'

+ 0 - 42
src/theme/BootstrapTheme.ts

@@ -1,42 +0,0 @@
-import Theme from './Theme'
-
-export default class BootstrapTheme extends Theme {
-}
-
-BootstrapTheme.prototype.classes = {
-  widget: 'fc-bootstrap3',
-
-  tableGrid: 'table-bordered', // avoid `table` class b/c don't want margins. only border color
-  tableList: 'table table-striped', // `table` class creates bottom margin but who cares
-
-  buttonGroup: 'btn-group',
-  button: 'btn btn-default',
-  stateActive: 'active',
-  stateDisabled: 'disabled',
-
-  today: 'alert alert-info', // the plain `info` class requires `.table`, too much to ask
-
-  popover: 'panel panel-default',
-  popoverHeader: 'panel-heading',
-  popoverContent: 'panel-body',
-
-  // day grid
-  headerRow: 'panel-default', // avoid `panel` class b/c don't want margins/radius. only border color
-  dayRow: 'panel-default', // "
-
-  // list view
-  listView: 'panel panel-default'
-}
-
-BootstrapTheme.prototype.baseIconClass = 'glyphicon'
-BootstrapTheme.prototype.iconClasses = {
-  close: 'glyphicon-remove',
-  prev: 'glyphicon-chevron-left',
-  next: 'glyphicon-chevron-right',
-  prevYear: 'glyphicon-backward',
-  nextYear: 'glyphicon-forward'
-}
-
-BootstrapTheme.prototype.iconOverrideOption = 'bootstrapGlyphicons'
-BootstrapTheme.prototype.iconOverrideCustomButtonOption = 'bootstrapGlyphicon'
-BootstrapTheme.prototype.iconOverridePrefix = 'glyphicon-'

+ 4 - 2
src/theme/config.ts

@@ -3,8 +3,10 @@ import { defineThemeSystem } from './ThemeRegistry'
 
 import StandardTheme from './StandardTheme'
 import JqueryUiTheme from './JqueryUiTheme'
-import BootstrapTheme from './BootstrapTheme'
+import Bootstrap3Theme from './Bootstrap3Theme'
+import Bootstrap4Theme from './Bootstrap4Theme'
 
 defineThemeSystem('standard', StandardTheme)
 defineThemeSystem('jquery-ui', JqueryUiTheme)
-defineThemeSystem('bootstrap3', BootstrapTheme)
+defineThemeSystem('bootstrap3', Bootstrap3Theme)
+defineThemeSystem('bootstrap4', Bootstrap4Theme)

+ 5 - 3
src/types/input-types.ts

@@ -65,7 +65,8 @@ export interface CustomButtonInput {
   text: string
   icon?: string
   themeIcon?: string
-  bootstrapGlyphicon?: string
+  bootstrapGlyphicon?: string,
+  bootstrapFontAwesome?: string,
   click(element: JQuery): void
 }
 
@@ -120,9 +121,10 @@ export interface OptionsInputBase {
   footer?: boolean | ToolbarInput
   customButtons?: { [name: string]: CustomButtonInput }
   buttonIcons?: boolean | ButtonIconsInput
-  themeSystem?: 'standard' | 'bootstrap3' | 'jquery-ui'
+  themeSystem?: 'standard' | 'bootstrap3' | 'bootstrap4' | 'jquery-ui'
   themeButtonIcons?: boolean | ButtonIconsInput
-  bootstrapGlyphicons?: boolean | ButtonIconsInput
+  bootstrapGlyphicons?: boolean | ButtonIconsInput,
+  bootstrapFontAwesome?: boolean | ButtonIconsInput,
   firstDay?: number
   isRTL?: boolean
   weekends?: boolean

+ 2 - 1
tests/automated/legacy/destroy.js

@@ -24,7 +24,8 @@ describe('destroy', function() {
 
   describeOptions('theme', {
     'when jquery-ui theme': 'jquery-ui',
-    'when bootstrap theme': 'bootstrap3'
+    'when bootstrap theme': 'bootstrap3',
+    'when bootstrap4 theme': 'bootstrap4'
   }, function() {
     it('cleans up all classNames on the root element', function() {
       initCalendar()

+ 33 - 0
tests/automated/theme/bootstrap4.js

@@ -0,0 +1,33 @@
+
+describe('bootstrap4 theme', function() {
+  pushOptions({ themeSystem: 'bootstrap4' })
+
+  describe('fa', function() {
+    pushOptions({
+      header: { left: '', center: '', right: 'next' }
+    })
+
+    it('renders default', function() {
+      initCalendar()
+      expect($('.fa')).toHaveClass('fa-chevron-right')
+    })
+
+    it('renders a customized icon', function() {
+      initCalendar({
+        bootstrapFontAwesome: {
+          next: 'asdf'
+        }
+      })
+      expect($('.fa')).toHaveClass('fa-asdf')
+    })
+
+    it('renders text when specified as false', function() {
+      initCalendar({
+        bootstrapFontAwesome: false
+      })
+      expect($('.fa')).not.toBeInDOM()
+      expect($('.fc-next-button')).toHaveText('next')
+    })
+  })
+
+})

+ 12 - 0
tests/automated/theme/switching.js

@@ -15,6 +15,13 @@ describe('theme switching', function() {
     verifyBootstrapTheme()
   })
 
+  it('can switch from jquery-ui to boostrap4', function() {
+    initCalendar({ themeSystem: 'jquery-ui' })
+    verifyJqueryUiTheme()
+    currentCalendar.option('themeSystem', 'bootstrap4')
+    verifyBootstrap4Theme()
+  })
+
 
   function verifyStandardTheme() {
     expect($('.fc-unthemed')).toBeInDOM()
@@ -31,4 +38,9 @@ describe('theme switching', function() {
     expect($('.fc .table-bordered')).toBeInDOM()
   }
 
+  function verifyBootstrap4Theme() {
+    expect($('.fc-bootstrap4')).toBeInDOM()
+    expect($('.fc .table-bordered')).toBeInDOM()
+  }
+
 })

+ 12 - 0
tests/automated/toolbar/customButtons.js

@@ -46,4 +46,16 @@ describe('customButtons', function() {
 
     expect($('.fc-mybutton-button .glyphicon')).toHaveClass('glyphicon-asdf')
   })
+
+  it('can specify a bootstrap4 font-awesome icon', function() {
+    initCalendar({
+      themeSystem: 'bootstrap4',
+      customButtons: {
+        mybutton: { bootstrapFontAwesome: 'asdf' }
+      },
+      header: { left: 'mybutton', center: '', right: '' }
+    })
+
+    expect($('.fc-mybutton-button .fa')).toHaveClass('fa-asdf')
+  })
 })

+ 129 - 0
tests/manual/bootstrap4.html

@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8' />
+<link href='../../dist/fullcalendar.css' rel='stylesheet' />
+<link href='../../dist/fullcalendar.print.css' rel='stylesheet' media='print' />
+<script src='../../node_modules/moment/moment.js'></script>
+<script src='../../node_modules/jquery/dist/jquery.js'></script>
+<script src='../../dist/fullcalendar.js'></script>
+
+<!-- using CDN for Bootstrap4 as the project currently depends on Bootstrap 3 -->
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
+<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
+<script>
+
+  $(document).ready(function() {
+    
+    $('#calendar').fullCalendar({
+      customButtons: {
+        myCustomButton: {
+          text: 'custom!',
+          bootstrapFontAwesome: 'fa-bell',
+          click: function() {
+              alert('clicked the custom button!');
+          }
+        }
+      },
+      header: {
+        left: 'prevYear,prev,today,next,nextYear',
+        center: 'title',
+        right: 'myCustomButton month,agendaWeek,agendaDay'
+      },
+      themeSystem: 'bootstrap4',
+      bootstrapFontAwesome: {
+        close: 'fa-times-circle',
+        prev: 'fa-caret-left',
+        next: 'fa-caret-right',
+        prevYear: 'fa-arrow-left',
+        nextYear: 'fa-arrow-right',
+        month: 'fa-calendar'
+      },
+      // bootstrapFontAwesome: false,
+      defaultDate: '2014-08-12',
+      editable: true,
+      eventLimit: true, // allow "more" link when too many events
+      events: [
+        {
+          title: 'All Day Event',
+          start: '2014-08-01'
+        },
+        {
+          title: 'Long Event',
+          start: '2014-08-07',
+          end: '2014-08-10'
+        },
+        {
+          id: 999,
+          title: 'Repeating Event',
+          start: '2014-08-09T16:00:00'
+        },
+        {
+          id: 999,
+          title: 'Repeating Event',
+          start: '2014-08-16T16:00:00'
+        },
+        {
+          title: 'Conference',
+          start: '2014-08-11',
+          end: '2014-08-13'
+        },
+        {
+          title: 'Meeting',
+          start: '2014-08-12T10:30:00',
+          end: '2014-08-12T12:30:00'
+        },
+        {
+          title: 'Lunch',
+          start: '2014-08-12T12:00:00'
+        },
+        {
+          title: 'Meeting',
+          start: '2014-08-12T14:30:00'
+        },
+        {
+          title: 'Happy Hour',
+          start: '2014-08-12T17:30:00'
+        },
+        {
+          title: 'Dinner',
+          start: '2014-08-12T20:00:00'
+        },
+        {
+          title: 'Birthday Party',
+          start: '2014-08-13T07:00:00'
+        },
+        {
+          title: 'Click for Google',
+          url: 'http://google.com/',
+          start: '2014-08-28'
+        }
+      ]
+    });
+    
+  });
+
+</script>
+<style>
+
+  body {
+    margin: 40px 10px;
+    padding: 0;
+    font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
+    font-size: 14px;
+  }
+
+  #calendar {
+    max-width: 900px;
+    margin: 0 auto;
+  }
+
+</style>
+</head>
+<body>
+
+  <div id='calendar'></div>
+
+</body>
+</html>