Saved: 2018-03-19 19:52
Torey Heinz
committed Mar 20, 2018
commit ad51d920120c4f34f4ca5db316089665330f4e15
Showing 18
changed files with
3149 additions
and 170 deletions
app/content_types/marine_estimate_requests.yml
+130
-0
| @@ | @@ -0,0 +1,130 @@ |
| + | # Human readable name of this type |
| + | name: Marine estimate requests |
| + | |
| + | # Lowercase, underscored handle used to access this type |
| + | slug: marine_estimate_requests |
| + | |
| + | # Explanatory text displayed in the back-office |
| + | description: A description of the content type for the editors |
| + | |
| + | # Slug of field used to identify entries by default, such as the title |
| + | label_field_name: name |
| + | |
| + | # Valid values: manually, created_at, updated_at, or the slug of any field |
| + | order_by: manually |
| + | |
| + | # Valid values: asc (ascending) and desc (descending). Set to asc by default. |
| + | # order_direction: asc |
| + | |
| + | # Specify a field slug to group entries by that field in the back-office. |
| + | # group_by: <your field> |
| + | |
| + | # Activate public 'create' API (e.g for a contact form) |
| + | # public_submission_enabled: false |
| + | |
| + | # Array of emails to be notified of new entries made with the public API |
| + | # public_submission_accounts: ['john@example.com'] |
| + | |
| + | # Control the display of the content type in the back-office. |
| + | # display_settings: |
| + | # seo: false # display the SEO tab for the content entries |
| + | # advanced: false # display the Advanced tab for the content entries |
| + | # position: 1 # position in the sidebar menu |
| + | # hidden: false # hidden for authors? |
| + | |
| + | # By default, the back-office displays the _label property (see label_field_name) of the content entry. This can be modified by writing your own Liquid template below: |
| + | # entry_template: '<a href="{{ link }}">{{ entry._label }}</a>' # The default template |
| + | |
| + | # A list describing each field |
| + | fields: |
| + | - name: # The lowercase, underscored name of the field |
| + | label: Name # Human readable name of the field |
| + | type: string |
| + | required: true |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - email: # The lowercase, underscored name of the field |
| + | label: Email # Human readable name of the field |
| + | type: string |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - phone: # The lowercase, underscored name of the field |
| + | label: Phone # Human readable name of the field |
| + | type: string |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - vessel_description: # The lowercase, underscored name of the field |
| + | label: Vessel description # Human readable name of the field |
| + | type: string |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - hull_number: # The lowercase, underscored name of the field |
| + | label: Hull number # Human readable name of the field |
| + | type: string |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - location: # The lowercase, underscored name of the field |
| + | label: Location # Human readable name of the field |
| + | type: string |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - marina: # The lowercase, underscored name of the field |
| + | label: Marina # Human readable name of the field |
| + | type: string |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - completion_date: # The lowercase, underscored name of the field |
| + | label: Completion date # Human readable name of the field |
| + | type: string |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - message: # The lowercase, underscored name of the field |
| + | label: Message # Human readable name of the field |
| + | type: text |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | # text_formatting: html # html (uses rich text editor), markdown or text (uses plain text editor) |
| + | |
| + | - attachment_1: # The lowercase, underscored name of the field |
| + | label: Attachment 1 # Human readable name of the field |
| + | type: file |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - attachment_2: # The lowercase, underscored name of the field |
| + | label: Attachment 2 # Human readable name of the field |
| + | type: file |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - attachment_3: # The lowercase, underscored name of the field |
| + | label: Attachment 3 # Human readable name of the field |
| + | type: file |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
| + | |
| + | - attachment_4: # The lowercase, underscored name of the field |
| + | label: Attachment 4 # Human readable name of the field |
| + | type: file |
| + | required: false |
| + | hint: Explanatory text displayed in the back office |
| + | localized: false |
app/views/pages/contact.liquid
+4
-4
| @@ | @@ -1,13 +1,13 @@ |
| --- | |
| - | title: Contact Us |
| - | handle: contact-us |
| + | title: Contact |
| + | handle: contact |
| slug: contact | |
| listed: true | |
| published: true | |
| is_layout: false | |
| editable_elements: | |
| "main/heading": "Contact a Real Person, Who Really Cares." | |
| - | "main/content": "Wheither you are ready to get start or still have some questions, feel free to reach out, and we'll assist you anyway we can." |
| + | "main/content": "Whether you are ready to get start or still have some questions, feel free to reach out, and we'll assist you anyway we can." |
| --- | |
| {% extends 'layouts/page' %} | |
| {% block 'main' %} | |
| @@ | @@ -43,7 +43,7 @@ editable_elements: |
| </div> | |
| <div class="column medium-6"> | |
| - | {% model_form 'customer_messages', success: '/contact-thank-you', error: '/contact', id: 'contact-form' %} |
| + | {% model_form 'customer_messages', success: '/thank-you', error: '/contact', id: 'contact-form' %} |
| {% if customer_message.errors %} | |
| <p>The following errors occured:</p> | |
| <ul> | |
app/views/pages/estimate.liquid
+41
-155
| @@ | @@ -1,166 +1,52 @@ |
| --- | |
| title: Estimate | |
| handle: estimate | |
| - | slug: get-a-free-estimate |
| - | listed: false |
| + | slug: estimate |
| + | listed: true |
| published: true | |
| is_layout: false | |
| editable_elements: | |
| - | "main/heading": "Get a Free Estimate" |
| - | "main/content": "Our customers are the best, and we are honored to be able to serve them. " |
| + | "main/heading": "We can wait to get started on your project!" |
| + | "main/content": "When you're ready move forward with you project, this is the place to start. The more information you can give use here, the sooner we can get you an estimate. <p class='lead'>Complete the form below to get a free Estimate.</p>" |
| --- | |
| - | {% extends 'layouts/page' %} |
| + | {% extends 'layouts/application' %} |
| {% block 'main' %} | |
| {% include 'page_header' %} | |
| - | <section class="estimate"> |
| - | <form class="webform-client-form MultiFile-intercepted" enctype="multipart/form-data" action="/request-estimate?service_url=https%3A//www.canvasinnovations.us/marine-services/upholstery&service_interest=Upholstery" method="post" id="webform-client-form-598" accept-charset="UTF-8"> |
| - | <div> |
| - | <div class="form-item webform-component webform-component-markup" id="webform-component-personal-information-title"> |
| - | <div class="row"> |
| - | <h3>Personal Information</h3> |
| - | <hr> |
| - | <div class="column medium-4"> |
| - | <label> |
| - | Name <small>(required)</small> |
| - | <input type="text" name="submitted[first_name]" value="" size="30" maxlength="128" class="form-text required"> |
| - | </label> |
| - | <label> |
| - | Email <small> (required)</small> |
| - | <input class="email form-text form-email required" type="email" id="edit-submitted-email-address" name="submitted[email_address]" size="30"> |
| - | </label> |
| - | <label> |
| - | Phone <small> (required)</small> |
| - | <input type="text" id="edit-submitted-phone-number" name="submitted[phone_number]" value="" size="15" maxlength="128" class="form-text required"> |
| - | </label> |
| - | </div> |
| - | <div class="column medium-8"> |
| - | <label> |
| - | Instructions, Comments, or Questions |
| - | <div class="form-textarea-wrapper"> |
| - | <textarea style="height: 280px" id="edit-submitted-instructions-comments-or-questions" name="submitted[instructions_comments_or_questions]" class="form-textarea"></textarea> |
| - | </div> |
| - | </label> |
| - | </div> |
| - | </div> |
| - | <hr> |
| - | <div class="row"> |
| - | <div class="column medium-8"> |
| - | <h3>Vessel Information</h3> |
| - | <hr> |
| - | <label> |
| - | Make/Model |
| - | <input type="text" id="edit-submitted-make-model" name="submitted[make_model]" value="" size="30" maxlength="128" class="form-text"> |
| - | </label> |
| - | <div class="form-item webform-component webform-component-number" id="webform-component-size"> |
| - | <label> |
| - | Size <small> (required)</small> |
| - | <input type="number" id="edit-submitted-size" name="submitted[size]" step="0.5" class="form-text form-number required"> <span class="field-suffix">Ft</span> |
| - | </label> |
| - | </div> |
| - | <label> |
| - | City <small> (required)</small> |
| - | <input type="text" id="edit-submitted-vessel-city" name="submitted[vessel_city]" value="" size="30" maxlength="128" class="form-text required"> |
| - | </label> |
| - | <div class="form-item webform-component webform-component-select" id="webform-component-vessel-state"> |
| - | <label> |
| - | State <small> (required)</small> |
| - | <select id="edit-submitted-vessel-state" name="submitted[vessel_state]" class="form-select required"> |
| - | <option value="" selected="selected">- Select -</option> |
| - | <option value="IL">Illinois</option> |
| - | <option value="IN">Indiana</option> |
| - | <option value="MI">Michigan</option> |
| - | <option value="OH">Ohio</option> |
| - | </select> |
| - | </label> |
| - | </div> |
| - | <label> |
| - | Zip Code <small> (required)</small> |
| - | <input type="text" id="edit-submitted-vessel-zip" name="submitted[vessel_zip]" value="" size="5" maxlength="128" class="form-text required"> |
| - | </label> |
| - | <label> |
| - | Marina |
| - | <input type="text" id="edit-submitted-marina" name="submitted[marina]" value="" size="30" maxlength="128" class="form-text"> |
| - | </label> |
| - | </div> |
| - | <div class="column medium-4"> |
| - | <label> |
| - | Services Requested <small> (required)</small> |
| - | <div id="edit-submitted-services-requested" class="form-checkboxes"> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-enclosures"> |
| - | </label> |
| - | <input type="checkbox" id="edit-submitted-services-requested-1" name="submitted[services_requested][enclosures]" value="enclosures" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-1">Enclosure </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-uphosltry"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-2" name="submitted[services_requested][uphosltry]" value="uphosltry" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-2">Upholstry </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-tops"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-3" name="submitted[services_requested][tops]" value="tops" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-3">Boat Tops </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-covers"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-4" name="submitted[services_requested][covers]" value="covers" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-4">Covers </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-windows"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-5" name="submitted[services_requested][windows]" value="windows" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-5">Bonded Windows </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-carpet"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-6" name="submitted[services_requested][carpet]" value="carpet" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-6">Carpet </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-dodger"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-7" name="submitted[services_requested][dodger]" value="dodger" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-7">Dodgers </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-headliners"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-8" name="submitted[services_requested][headliners]" value="headliners" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-8">Headliners </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-repairs"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-9" name="submitted[services_requested][repairs]" value="repairs" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-9">Repairs & Stitching </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-framebending"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-10" name="submitted[services_requested][framebending]" value="framebending" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-10">Custom Frame Bending </label> |
| - | </div> |
| - | <div class="form-item form-type-checkbox form-item-submitted-services-requested-misc"> |
| - | <input type="checkbox" id="edit-submitted-services-requested-11" name="submitted[services_requested][misc]" value="misc" class="form-checkbox"> |
| - | <label class="option" for="edit-submitted-services-requested-11">Misc/NA </label> |
| - | </div> |
| - | <label> |
| - | Vessel Images |
| - | <div class="MultiFile-wrap" id="edit-vessel-images-multi_wrap"> |
| - | <input class="form-item multi MultiFile-identifier-vessel-images-multi form-file jquery-once-1-processed MultiFile-applied" type="file" id="edit-vessel-images-multi" name="files[vessel_images_multi][]" size="60" value=""> |
| - | <div class="MultiFile-list" id="edit-vessel-images-multi_wrap_list"></div> |
| - | </div> |
| - | </label> |
| - | <div class="description">Please upload any relevant images.</div> |
| - | </div> |
| - | </div> |
| - | <div class="form-item webform-component webform-component-multifile" id="webform-component-vessel-images-multi"> |
| - | <div class="form-item form-type-file form-item-files-vessel-images-multi"> |
| + | <section class="row page {{ page.slug }}"> |
| + | <div class="column medium-6"> |
| + | <div id="form-wrapper" class="callout"> |
| + | <h2 class="text-center">{% editable_text "heading", line_break: false, format: 'raw', rows: 1 %}Heading{% endeditable_text %}</h2> |
| + | {% editable_text content %}Lorem ipsum{% endeditable_text %} |
| + | {% include 'estimate_form' %} |
| + | <hr> |
| + | <strong>Testimonial: </strong> |
| + | <div> |
| + | {% include 'random_testimonial' %} |
| + | </div> |
| + | </div> |
| + | </div> |
| + | <div class="column medium-6"> |
| + | <div id="testimonials-wrapper" class="callout" style="height: 1200px; overflow: hidden;"> |
| + | <p class="lead"><strong>Testimonials</strong></p> |
| + | {% include 'testimonials' %} |
| + | </div> |
| + | </div> |
| + | </section> |
| + | {% endblock %} |
| + | {% block body_bottom %} |
| + | <script type="text/javascript"> |
| + | $(function() { |
| + | $('#testimonials-wrapper').height($('#form-wrapper').height() + 78); |
| + | |
| + | $('#contact-form').on('submit', function(e) { |
| + | var form = $(this); |
| + | $('.robot-warning').addClass('hide') |
| - | </div> |
| - | <div class="outer"> |
| - | <div class="inner"></div> |
| - | </div> |
| - | <input type="hidden" name="submitted[vessel_images_multi][_fids]" value=""> |
| - | <input type="hidden" name="submitted[vessel_images_multi][_old_fids]"> |
| - | </div> |
| - | <input type="hidden" name="details[sid]"> |
| - | <input type="hidden" name="details[page_num]" value="1"> |
| - | <input type="hidden" name="details[page_count]" value="1"> |
| - | <input type="hidden" name="details[finished]" value="0"> |
| - | <input type="hidden" name="form_build_id" value="form-XlJ0zOK1V4N95GlwBuj7VP0EwSksg8EYPRx8hgFY8Ko"> |
| - | <input type="hidden" name="form_id" value="webform_client_form_598"> |
| - | <div class="form-actions form-wrapper" id="edit-actions"> |
| - | <input class="btn btn-primary form-submit" type="submit" id="edit-submit" name="op" value="Submit"> |
| - | </div> |
| - | </div> |
| - | </form> |
| - | </section> |
| + | if (grecaptcha.getResponse() == "") { |
| + | e.preventDefault(); |
| + | $('.robot-warning').removeClass('hide') |
| + | } |
| + | }); |
| + | }); |
| + | </script> |
| {% endblock %} | |
app/views/pages/index.liquid
+1
-1
| @@ | @@ -45,7 +45,7 @@ is_layout: false |
| <p class="lead"><a href="{% path_to service %}">{{ service.title }}</a></p> | |
| </div> | |
| <img src="{{ service.featured_image.url | resize: '400x300#' }}"> | |
| - | <div class="card-section"> |
| + | <div class="card-section hide-for-small-only"> |
| {{ service.brief }} | |
| </div> | |
| </div> | |
app/views/pages/testimonials.liquid
+1
-7
| @@ | @@ -22,13 +22,7 @@ editable_elements: |
| </p> | |
| </div> | |
| <hr class="thin"> | |
| - | {% assign testimonials = contents.testimonials.all | shuffle %} |
| - | {% for testimonial in testimonials %} |
| - | <p class="callout offwhite"> |
| - | {{ testimonial.content }}<br> |
| - | -- <strong>{{ testimonial.who }}</strong> |
| - | </p> |
| - | {% endfor %} |
| + | {% include 'testimonials' %} |
| </div> | |
| </div> | |
| </section> | |
app/views/pages/thank-you.liquid
+26
-0
| @@ | @@ -0,0 +1,26 @@ |
| + | --- |
| + | title: Thank You! |
| + | slug: thank-you |
| + | listed: false |
| + | published: true |
| + | is_layout: false |
| + | editable_elements: |
| + | "main/heading": "We'll be contacting you soon!" |
| + | "main/content": "We know you are excited to get started, while you wait, see what others have said." |
| + | --- |
| + | {% extends 'layouts/page' %} |
| + | {% block 'main' %} |
| + | {% include 'page_header' %} |
| + | <section class="row page {{ page.slug }}"> |
| + | <div class="column medium-8 small-centered"> |
| + | <div class="callout"> |
| + | <h2 class="text-center">{% editable_text "heading", line_break: false, format: 'raw', rows: 1 %}Heading{% endeditable_text %}</h2> |
| + | <div class="text-center"> |
| + | {% editable_text content %}Lorem ipsum{% endeditable_text %} |
| + | </div> |
| + | <hr class="thin"> |
| + | {% include 'testimonials' %} |
| + | </div> |
| + | </div> |
| + | </section> |
| + | {% endblock %} |
app/views/snippets/address_form.liquid
+13
-0
| @@ | @@ -0,0 +1,13 @@ |
| + | <label class="row"> |
| + | Project Address: |
| + | <input name="content[address]" required="true" type="text" value="{{marine_estimate_request.address}}"> |
| + | <input name="content[city]" required="true" type="text" value="{{marine_estimate_request.city}}"> |
| + | <select name="content[state]" required="true"> |
| + | <option value="" selected="selected">- Select -</option> |
| + | <option value="IL">Illinois</option> |
| + | <option value="IN">Indiana</option> |
| + | <option value="MI">Michigan</option> |
| + | <option value="OH">Ohio</option> |
| + | </select> |
| + | <input name="content[zip]" required="true" type="text" value="{{marine_estimate_request.zip}}"> |
| + | </label> |
app/views/snippets/estimate_form.liquid
+47
-0
| @@ | @@ -0,0 +1,47 @@ |
| + | {% model_form 'marine_estimate_requests', success: '/contact/thank-you', error: '/estimate', id: 'estimate-form' %} |
| + | {% if marine_estimate_request.errors %} |
| + | <p>The following errors occured:</p> |
| + | <ul> |
| + | {% for error in marine_estimate_request.errors %} |
| + | <li>{{error[0] | capitalize}} - {{error[1]}}</li> |
| + | {% endfor %} |
| + | </ul> |
| + | {% endif %} |
| + | <label> |
| + | Full Name:{% include 'required' %} |
| + | <input name="content[name]" required="true" type="text" value="{{marine_estimate_request.name}}"> |
| + | </label> |
| + | <label> |
| + | Best Email:{% include 'required' %} |
| + | <input name="content[email]" required="true" type="email" value="{{marine_estimate_request.email}}"> |
| + | </label> |
| + | <label> |
| + | Your Phone:{% include 'required' %} |
| + | <input name="content[phone]" required="true" type="tel" value="{{marine_estimate_request.phone}}"> |
| + | </label> |
| + | <label> |
| + | Project Address:{% include 'required' %} |
| + | <p class="help-text thin">Please enter complete address</p> |
| + | <textarea name="content[address]" rows="2" required="true" placeholder="11276 E. Lakewood Blvd. |
| + | Holland, MI 49424 ">{{marine_estimate_request.address}}</textarea> |
| + | </label> |
| + | <label> |
| + | Project Location: |
| + | <p class="help-text thin">When applicable include: Marina, Dock/Slip number, location on property, etc.</p> |
| + | <textarea name="content[vessel_description]" rows="2">{{marine_estimate_request.vessel_description}}</textarea> |
| + | </label> |
| + | <label> |
| + | Work to be Completed:{% include 'required' %} |
| + | <textarea class="autosize" name="content[message]" rows="6" required="true" >{{marine_estimate_request.message}}</textarea> |
| + | </label> |
| + | <label> |
| + | When would you like your project completed by? |
| + | <input name="content[completion_date]" type="date" > |
| + | </label> |
| + | </tr> |
| + | <div class="robot-warning hide callout text-center warning"> |
| + | Are you robot? |
| + | </div> |
| + | <div class="callout g-recaptcha text-center" data-sitekey="6LdbaUwUAAAAAFPucKMnLxCnYvIPBr3UQNOLYCE2"></div> |
| + | <input type="submit" class="button expanded large" value="Let's Get Started!"> |
| + | {% endmodel_form %} |
app/views/snippets/metatags.liquid
+1
-1
| @@ | @@ -14,4 +14,4 @@ |
| <meta property="og:image" content="{{ 'logo.png' | theme_image_url }}" /> | |
| <meta property="og:site_name" content="{{ site.name }}" /> | |
| <link rel="shortcut icon" href="{{ 'favicon.ico' | theme_image_url }}"> | |
| - | |
| + | <meta name="trumbowyg-icons-path" content="{{ 'trumbowyg-icons.svg' | theme_image_url }}"> |
app/views/snippets/required.liquid
+1
-0
| @@ | @@ -0,0 +1 @@ |
| + | <sup style="color: #7A3C19"><em>(required)</em></sup> |
app/views/snippets/testimonials.liquid
+7
-0
| @@ | @@ -0,0 +1,7 @@ |
| + | {% assign testimonial_list = contents.testimonials.all | shuffle %} |
| + | {% for testimonial in testimonial_list limit:10 %} |
| + | <p class="callout offwhite"> |
| + | {{ testimonial.content }}<br> |
| + | -- <strong>{{ testimonial.who }}</strong> |
| + | </p> |
| + | {% endfor %} |
data/marine_estimate_requests.yml
+44
-0
| @@ | @@ -0,0 +1,44 @@ |
| + | - "Sample 1": |
| + | email: "Vel voluptas est placeat deleniti in beatae." |
| + | phone: "Assumenda molestias eligendi id enim praesentium quia quaerat nihil." |
| + | vessel_description: "Est voluptas doloremque ea." |
| + | hull_number: "Eos veniam fugiat aspernatur consequatur dolor nemo." |
| + | location: "Quis alias et voluptatem." |
| + | marina: "Voluptate officia ipsam veniam eaque error iste nostrum." |
| + | completion_date: "Vel sunt eos et non." |
| + | message: "Cumque harum cupiditate natus consequatur ea itaque at. Optio hic illo quasi provident. Magnam voluptatum et tempora dolores fuga atque. Enim doloribus quasi eum et est." |
| + | # attachment_1: /samples/marine_estimate_requests/yourfile.txt # Path to a file in the public/samples folder or to a remote and external file. |
| + | |
| + | - "Sample 2": |
| + | email: "Ipsum qui eum totam facere adipisci voluptatem." |
| + | phone: "A numquam quo rem velit facere adipisci voluptatem." |
| + | vessel_description: "Porro rerum laboriosam eveniet eligendi quisquam." |
| + | hull_number: "Non laborum ad dicta dolore iusto cupiditate." |
| + | location: "Consequatur tempora fugit autem ea blanditiis eum aut ex." |
| + | marina: "Voluptate sed maxime explicabo dolor." |
| + | completion_date: "Ea tempore repellat esse ut quam." |
| + | message: "Est voluptatem dolorem esse. Quo perspiciatis ut omnis molestiae porro ut libero. Neque omnis rerum repellendus animi minima." |
| + | # attachment_1: /samples/marine_estimate_requests/yourfile.txt # Path to a file in the public/samples folder or to a remote and external file. |
| + | |
| + | - "Sample 3": |
| + | email: "Fugit ducimus alias velit eum esse." |
| + | phone: "Non quo laborum aut ducimus modi aperiam in consequatur." |
| + | vessel_description: "Nobis et natus quis." |
| + | hull_number: "Corrupti fugiat dicta quae nisi quos ea ab qui." |
| + | location: "Autem molestiae ut distinctio corporis optio voluptatem quisquam." |
| + | marina: "Reprehenderit enim velit minima." |
| + | completion_date: "Qui repellat quo et similique." |
| + | message: "Illum aut sed rerum sint. Qui exercitationem praesentium. Sit velit non voluptatem odit deserunt non. Tenetur ab possimus impedit." |
| + | # attachment_1: /samples/marine_estimate_requests/yourfile.txt # Path to a file in the public/samples folder or to a remote and external file. |
| + | |
| + | - "Sample 4": |
| + | email: "Enim vero dicta cumque dolore voluptatem aut." |
| + | phone: "Fugit voluptas et omnis non quis ut." |
| + | vessel_description: "Numquam ut quibusdam earum veniam." |
| + | hull_number: "Omnis possimus fuga itaque non recusandae ducimus modi." |
| + | location: "Id provident alias ut reiciendis qui dolorem." |
| + | marina: "Et voluptatem sed magnam ullam dolorem aperiam." |
| + | completion_date: "Unde quia aperiam explicabo vel laboriosam occaecati." |
| + | message: "Aut porro fuga. Ea aperiam corrupti quia necessitatibus ut est optio. Et saepe quo illo at." |
| + | # attachment_1: /samples/marine_estimate_requests/yourfile.txt # Path to a file in the public/samples folder or to a remote and external file. |
| + | |
public/images/trumbowyg-icons.svg
+1
-0
| @@ | @@ -0,0 +1 @@ |
| + | <svg xmlns="http://www.w3.org/2000/svg"><symbol id="trumbowyg-blockquote" viewBox="0 0 72 72"><path d="M21.3 31.9h-.6c.8-1.2 1.9-2.2 3.4-3.2 2.1-1.4 5-2.7 9.2-3.3l-1.4-8.9c-4.7.7-8.5 2.1-11.7 4-2.4 1.4-4.3 3.1-5.8 4.9-2.3 2.7-3.7 5.7-4.5 8.5-.8 2.8-1 5.4-1 7.5 0 2.3.3 4 .4 4.8 0 .1.1.3.1.4 1.2 5.4 6.1 9.5 11.9 9.5 6.7 0 12.2-5.4 12.2-12.2s-5.5-12-12.2-12zM49.5 31.9h-.6c.8-1.2 1.9-2.2 3.4-3.2 2.1-1.4 5-2.7 9.2-3.3l-1.4-8.9c-4.7.7-8.5 2.1-11.7 4-2.4 1.4-4.3 3.1-5.8 4.9-2.3 2.7-3.7 5.7-4.5 8.5-.8 2.8-1 5.4-1 7.5 0 2.3.3 4 .4 4.8 0 .1.1.3.1.4 1.2 5.4 6.1 9.5 11.9 9.5 6.7 0 12.2-5.4 12.2-12.2s-5.5-12-12.2-12z"/></symbol><symbol id="trumbowyg-bold" viewBox="0 0 72 72"><path d="M51.1 37.8c-1.1-1.4-2.5-2.5-4.2-3.3 1.2-.8 2.1-1.8 2.8-3 1-1.6 1.5-3.5 1.5-5.3 0-2-.6-4-1.7-5.8-1.1-1.8-2.8-3.2-4.8-4.1-2-.9-4.6-1.3-7.8-1.3h-16v42h16.3c2.6 0 4.8-.2 6.7-.7 1.9-.5 3.4-1.2 4.7-2.1 1.3-1 2.4-2.4 3.2-4.1.9-1.7 1.3-3.6 1.3-5.7.2-2.5-.5-4.7-2-6.6zM40.8 50.2c-.6.1-1.8.2-3.4.2h-9V38.5h8.3c2.5 0 4.4.2 5.6.6 1.2.4 2 1 2.7 2 .6.9 1 2 1 3.3 0 1.1-.2 2.1-.7 2.9-.5.9-1 1.5-1.7 1.9-.8.4-1.7.8-2.8 1zm2.6-20.4c-.5.7-1.3 1.3-2.5 1.6-.8.3-2.5.4-4.8.4h-7.7V21.6h7.1c1.4 0 2.6 0 3.6.1s1.7.2 2.2.4c1 .3 1.7.8 2.2 1.7.5.9.8 1.8.8 3-.1 1.3-.4 2.2-.9 3z"/></symbol><symbol id="trumbowyg-close" viewBox="0 0 72 72"><path d="M57 20.5l-5.4-5.4-15.5 15.5-15.6-15.5-5.4 5.4L30.7 36 15.1 51.5l5.4 5.4 15.6-15.5 15.5 15.5 5.4-5.4L41.5 36z"/></symbol><symbol id="trumbowyg-create-link" viewBox="0 0 72 72"><path d="M31.1 48.9l-6.7 6.7c-.8.8-1.6.9-2.1.9s-1.4-.1-2.1-.9L15 50.4c-1.1-1.1-1.1-3.1 0-4.2l6.1-6.1.2-.2 6.5-6.5c-1.2-.6-2.5-.9-3.8-.9-2.3 0-4.6.9-6.3 2.6L11 41.8c-3.5 3.5-3.5 9.2 0 12.7l5.2 5.2c1.7 1.7 4 2.6 6.3 2.6s4.6-.9 6.3-2.6l6.7-6.7c2.5-2.6 3.1-6.7 1.5-10l-5.9 5.9zM38.7 22.5l6.7-6.7c.8-.8 1.6-.9 2.1-.9s1.4.1 2.1.9l5.2 5.2c1.1 1.1 1.1 3.1 0 4.2l-6.1 6.1-.2.2L42 38c1.2.6 2.5.9 3.8.9 2.3 0 4.6-.9 6.3-2.6l6.7-6.7c3.5-3.5 3.5-9.2 0-12.7l-5.2-5.2c-1.7-1.7-4-2.6-6.3-2.6s-4.6.9-6.3 2.6l-6.7 6.7c-2.7 2.7-3.3 6.9-1.7 10.2l6.1-6.1c0 .1 0 .1 0 0z"/><path d="M44.2 30.5c.2-.2.4-.6.4-.9 0-.3-.1-.6-.4-.9l-2.3-2.3c-.3-.2-.6-.4-.9-.4-.3 0-.6.1-.9.4L25.9 40.6c-.2.2-.4.6-.4.9 0 .3.1.6.4.9l2.3 2.3c.2.2.6.4.9.4.3 0 .6-.1.9-.4l14.2-14.2zM49.9 55.4h-8.5v-5h8.5v-8.9h5.2v8.9h8.5v5h-8.5v8.9h-5.2v-8.9z"/></symbol><symbol id="trumbowyg-del" viewBox="0 0 72 72"><path d="M45.8 45c0 1-.3 1.9-.9 2.8-.6.9-1.6 1.6-3 2.1s-3.1.8-5 .8c-2.1 0-4-.4-5.7-1.1-1.7-.7-2.9-1.7-3.6-2.7-.8-1.1-1.3-2.6-1.5-4.5l-.1-.8-6.7.6v.9c.1 2.8.9 5.4 2.3 7.6 1.5 2.3 3.5 4 6.1 5.1 2.6 1.1 5.7 1.6 9.4 1.6 2.9 0 5.6-.5 8-1.6 2.4-1.1 4.3-2.7 5.6-4.7 1.3-2 2-4.2 2-6.5 0-1.6-.3-3.1-.9-4.5l-.2-.6H44c0 .1 1.8 2.3 1.8 5.5zM29 28.9c-.8-.8-1.2-1.7-1.2-2.9 0-.7.1-1.3.4-1.9.3-.6.7-1.1 1.4-1.6.6-.5 1.4-.9 2.5-1.1 1.1-.3 2.4-.4 3.9-.4 2.9 0 5 .6 6.3 1.7 1.3 1.1 2.1 2.7 2.4 5.1l.1.9 6.8-.5v-.9c-.1-2.5-.8-4.7-2.1-6.7s-3.2-3.5-5.6-4.5c-2.4-1-5.1-1.5-8.1-1.5-2.8 0-5.3.5-7.6 1.4-2.3 1-4.2 2.4-5.4 4.3-1.2 1.9-1.9 3.9-1.9 6.1 0 1.7.4 3.4 1.2 4.9l.3.5h11.8c-2.3-.9-3.9-1.7-5.2-2.9zm13.3-6.2zM22.7 20.3zM13 34.1h46.1v3.4H13z"/></symbol><symbol id="trumbowyg-em" viewBox="0 0 72 72"><path d="M26 57l10.1-42h7.2L33.2 57H26z"/></symbol><symbol id="trumbowyg-fontsize" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 4v3h5v12h3V7h5V4H9zm-6 8h3v7h3v-7h3V9H3v3z"/></symbol><symbol id="trumbowyg-fullscreen" viewBox="0 0 72 72"><path d="M25.2 7.1H7.1v17.7l6.7-6.5 10.5 10.5 4.5-4.5-10.4-10.5zM47.2 7.1l6.5 6.7-10.5 10.5 4.5 4.5 10.5-10.4 6.7 6.8V7.1zM47.7 43.2l-4.5 4.5 10.4 10.5-6.8 6.7h18.1V47.2l-6.7 6.5zM24.3 43.2L13.8 53.6l-6.7-6.8v18.1h17.7l-6.5-6.7 10.5-10.5z"/><path fill="currentColor" d="M10.7 28.8h18.1V11.2l-6.6 6.4L11.6 7.1l-4.5 4.5 10.5 10.5zM60.8 28.8l-6.4-6.6 10.5-10.6-4.5-4.5-10.5 10.5-6.7-6.9v18.1zM60.4 64.9l4.5-4.5-10.5-10.5 6.9-6.7H43.2v17.6l6.6-6.4zM11.6 64.9l10.5-10.5 6.7 6.9V43.2H11.1l6.5 6.6L7.1 60.4z"/></symbol><symbol id="trumbowyg-h1" viewBox="0 0 72 72"><path d="M6.4 14.9h7.4v16.7h19.1V14.9h7.4V57h-7.4V38H13.8v19H6.4V14.9zM47.8 22.5c1.4 0 2.8-.1 4.1-.4 1.3-.2 2.5-.6 3.6-1.2 1.1-.5 2-1.3 2.8-2.1.8-.9 1.3-1.9 1.5-3.2h5.5v41.2h-7.4v-29H47.8v-5.3z"/></symbol><symbol id="trumbowyg-h2" viewBox="0 0 72 72"><path d="M1.5 14.9h7.4v16.7H28V14.9h7.4V57H28V38H8.8v19H1.5V14.9zM70.2 56.9H42c0-3.4.9-6.4 2.5-9s3.8-4.8 6.6-6.7c1.3-1 2.7-1.9 4.2-2.9 1.5-.9 2.8-1.9 4-3 1.2-1.1 2.2-2.2 3-3.4.8-1.2 1.2-2.7 1.2-4.3 0-.7-.1-1.5-.3-2.4s-.5-1.6-1-2.4c-.5-.7-1.2-1.3-2.1-1.8-.9-.5-2.1-.7-3.5-.7-1.3 0-2.4.3-3.3.8s-1.6 1.3-2.1 2.2-.9 2-1.2 3.3c-.3 1.3-.4 2.6-.4 4.1h-6.7c0-2.3.3-4.4.9-6.3.6-1.9 1.5-3.6 2.7-5 1.2-1.4 2.7-2.5 4.4-3.3 1.7-.8 3.8-1.2 6.1-1.2 2.5 0 4.6.4 6.3 1.2 1.7.8 3.1 1.9 4.1 3.1 1 1.3 1.8 2.6 2.2 4.1.4 1.5.6 2.9.6 4.2 0 1.6-.3 3.1-.8 4.5-.5 1.3-1.2 2.6-2.1 3.7-.9 1.1-1.8 2.2-2.9 3.1-1.1.9-2.2 1.8-3.4 2.7-1.2.8-2.4 1.6-3.5 2.4-1.2.7-2.3 1.5-3.3 2.2-1 .7-1.9 1.5-2.6 2.3-.7.8-1.3 1.7-1.5 2.6h20.1v5.9z"/></symbol><symbol id="trumbowyg-h3" viewBox="0 0 72 72"><path d="M1.4 14.5h7.4v16.7h19.1V14.5h7.4v42.1h-7.4v-19H8.8v19H1.4V14.5zM53.1 32.4c1.1 0 2.2 0 3.3-.2 1.1-.2 2.1-.5 2.9-1 .9-.5 1.6-1.2 2.1-2 .5-.9.8-1.9.8-3.2 0-1.8-.6-3.2-1.8-4.2-1.2-1.1-2.7-1.6-4.6-1.6-1.2 0-2.2.2-3.1.7-.9.5-1.6 1.1-2.2 1.9-.6.8-1 1.7-1.3 2.7-.3 1-.4 2-.4 3.1h-6.7c.1-2 .5-3.9 1.1-5.6.7-1.7 1.6-3.2 2.7-4.4s2.6-2.2 4.2-2.9c1.6-.7 3.5-1.1 5.6-1.1 1.6 0 3.2.2 4.7.7 1.6.5 2.9 1.2 4.2 2.1 1.2.9 2.2 2.1 3 3.4.7 1.4 1.1 3 1.1 4.8 0 2.1-.5 3.9-1.4 5.4-.9 1.6-2.4 2.7-4.4 3.4v.1c2.4.5 4.2 1.6 5.5 3.5 1.3 1.9 2 4.1 2 6.8 0 2-.4 3.7-1.2 5.3-.8 1.6-1.8 2.9-3.2 3.9-1.3 1.1-2.9 1.9-4.7 2.5-1.8.6-3.6.9-5.6.9-2.4 0-4.5-.3-6.3-1s-3.3-1.7-4.5-2.9c-1.2-1.3-2.1-2.8-2.7-4.5-.6-1.8-1-3.7-1-5.9h6.7c-.1 2.5.5 4.6 1.9 6.3 1.3 1.7 3.3 2.5 5.9 2.5 2.2 0 4.1-.6 5.6-1.9 1.5-1.3 2.3-3.1 2.3-5.4 0-1.6-.3-2.9-.9-3.8-.6-.9-1.5-1.7-2.5-2.2-1-.5-2.2-.8-3.4-.9-1.3-.1-2.6-.2-3.9-.1v-5.2z"/></symbol><symbol id="trumbowyg-h4" viewBox="0 0 72 72"><path d="M1.5 14.9h7.4v16.7H28V14.9h7.4V57H28V38H8.9v19H1.5V14.9zM70.5 47.2h-5.3V57h-6.4v-9.8H41.2v-6.7l17.7-24.8h6.4v26.2h5.3v5.3zm-24.2-5.3h12.5V23.7h-.1L46.3 41.9z"/></symbol><symbol id="trumbowyg-horizontal-rule" viewBox="0 0 72 72"><path d="M9.1 32h54v8h-54z"/></symbol><symbol id="trumbowyg-insert-image" viewBox="0 0 72 72"><path d="M64 17v38H8V17h56m8-8H0v54h72V9z"/><path d="M17.5 22C15 22 13 24 13 26.5s2 4.5 4.5 4.5 4.5-2 4.5-4.5-2-4.5-4.5-4.5zM16 50h27L29.5 32zM36 36.2l8.9-8.5L60.2 50H45.9S35.6 35.9 36 36.2z"/></symbol><symbol id="trumbowyg-italic" viewBox="0 0 72 72"><path d="M26 57l10.1-42h7.2L33.2 57H26z"/></symbol><symbol id="trumbowyg-justify-center" viewBox="0 0 72 72"><path d="M9 14h54v8H9zM9 50h54v8H9zM18 32h36v8H18z"/></symbol><symbol id="trumbowyg-justify-full" viewBox="0 0 72 72"><path d="M9 14h54v8H9zM9 50h54v8H9zM9 32h54v8H9z"/></symbol><symbol id="trumbowyg-justify-left" viewBox="0 0 72 72"><path d="M9 14h54v8H9zM9 50h54v8H9zM9 32h36v8H9z"/></symbol><symbol id="trumbowyg-justify-right" viewBox="0 0 72 72"><path d="M9 14h54v8H9zM9 50h54v8H9zM27 32h36v8H27z"/></symbol><symbol id="trumbowyg-lineheight" viewBox="0 0 72 72"><path d="M31 14h36v8H31zM31 50h36v8H31zM31 32h30v8H31z"/><path stroke-miterlimit="10" fill="none" stroke="currentColor" stroke-width="3.6428" d="M7.82 47.207l8.332 8.15 8.106-8.15M24.276 24.635l-8.333-8.15-8.105 8.15"/><path d="M14.347 53.761v-36h3.385v36z"/></symbol><symbol id="trumbowyg-link" viewBox="0 0 72 72"><path d="M30.9 49.1l-6.7 6.7c-.8.8-1.6.9-2.1.9s-1.4-.1-2.1-.9l-5.2-5.2c-1.1-1.1-1.1-3.1 0-4.2l6.1-6.1.2-.2 6.5-6.5c-1.2-.6-2.5-.9-3.8-.9-2.3 0-4.6.9-6.3 2.6L10.8 42c-3.5 3.5-3.5 9.2 0 12.7l5.2 5.2c1.7 1.7 4 2.6 6.3 2.6s4.6-.9 6.3-2.6l6.7-6.7C38 50.5 38.6 46.3 37 43l-6.1 6.1zM38.5 22.7l6.7-6.7c.8-.8 1.6-.9 2.1-.9s1.4.1 2.1.9l5.2 5.2c1.1 1.1 1.1 3.1 0 4.2l-6.1 6.1-.2.2-6.5 6.5c1.2.6 2.5.9 3.8.9 2.3 0 4.6-.9 6.3-2.6l6.7-6.7c3.5-3.5 3.5-9.2 0-12.7l-5.2-5.2c-1.7-1.7-4-2.6-6.3-2.6s-4.6.9-6.3 2.6l-6.7 6.7c-2.7 2.7-3.3 6.9-1.7 10.2l6.1-6.1z"/><path d="M44.1 30.7c.2-.2.4-.6.4-.9 0-.3-.1-.6-.4-.9l-2.3-2.3c-.2-.2-.6-.4-.9-.4-.3 0-.6.1-.9.4L25.8 40.8c-.2.2-.4.6-.4.9 0 .3.1.6.4.9l2.3 2.3c.2.2.6.4.9.4.3 0 .6-.1.9-.4l14.2-14.2z"/></symbol><symbol id="trumbowyg-ordered-list" viewBox="0 0 72 72"><path d="M27 14h36v8H27zM27 50h36v8H27zM27 32h36v8H27zM11.8 15.8V22h1.8v-7.8h-1.5l-2.1 1 .3 1.3zM12.1 38.5l.7-.6c1.1-1 2.1-2.1 2.1-3.4 0-1.4-1-2.4-2.7-2.4-1.1 0-2 .4-2.6.8l.5 1.3c.4-.3 1-.6 1.7-.6.9 0 1.3.5 1.3 1.1 0 .9-.9 1.8-2.6 3.3l-1 .9V40H15v-1.5h-2.9zM13.3 53.9c1-.4 1.4-1 1.4-1.8 0-1.1-.9-1.9-2.6-1.9-1 0-1.9.3-2.4.6l.4 1.3c.3-.2 1-.5 1.6-.5.8 0 1.2.3 1.2.8 0 .7-.8.9-1.4.9h-.7v1.3h.7c.8 0 1.6.3 1.6 1.1 0 .6-.5 1-1.4 1-.7 0-1.5-.3-1.8-.5l-.4 1.4c.5.3 1.3.6 2.3.6 2 0 3.2-1 3.2-2.4 0-1.1-.8-1.8-1.7-1.9z"/></symbol><symbol id="trumbowyg-p" viewBox="0 0 72 72"><path d="M47.8 15.1H30.1c-4.7 0-8.5 3.7-8.5 8.4s3.7 8.4 8.4 8.4v25h7V19.8h3v37.1h4.1V19.8h3.7v-4.7z"/></symbol><symbol id="trumbowyg-redo" viewBox="0 0 72 72"><path d="M10.8 51.2c0-5.1 2.1-9.7 5.4-13.1 3.3-3.3 8-5.4 13.1-5.4H46v-12L61.3 36 45.9 51.3V39.1H29.3c-3.3 0-6.4 1.3-8.5 3.5-2.2 2.2-3.5 5.2-3.5 8.5h-6.5z"/></symbol><symbol id="trumbowyg-removeformat" viewBox="0 0 72 72"><path d="M58.2 54.6L52 48.5l3.6-3.6 6.1 6.1 6.4-6.4 3.8 3.8-6.4 6.4 6.1 6.1-3.6 3.6-6.1-6.1-6.4 6.4-3.7-3.8 6.4-6.4zM21.7 52.1H50V57H21.7zM18.8 15.2h34.1v6.4H39.5v24.2h-7.4V21.5H18.8v-6.3z"/></symbol><symbol id="trumbowyg-strikethrough" viewBox="0 0 72 72"><path d="M45.8 45c0 1-.3 1.9-.9 2.8-.6.9-1.6 1.6-3 2.1s-3.1.8-5 .8c-2.1 0-4-.4-5.7-1.1-1.7-.7-2.9-1.7-3.6-2.7-.8-1.1-1.3-2.6-1.5-4.5l-.1-.8-6.7.6v.9c.1 2.8.9 5.4 2.3 7.6 1.5 2.3 3.5 4 6.1 5.1 2.6 1.1 5.7 1.6 9.4 1.6 2.9 0 5.6-.5 8-1.6 2.4-1.1 4.3-2.7 5.6-4.7 1.3-2 2-4.2 2-6.5 0-1.6-.3-3.1-.9-4.5l-.2-.6H44c0 .1 1.8 2.3 1.8 5.5zM29 28.9c-.8-.8-1.2-1.7-1.2-2.9 0-.7.1-1.3.4-1.9.3-.6.7-1.1 1.4-1.6.6-.5 1.4-.9 2.5-1.1 1.1-.3 2.4-.4 3.9-.4 2.9 0 5 .6 6.3 1.7 1.3 1.1 2.1 2.7 2.4 5.1l.1.9 6.8-.5v-.9c-.1-2.5-.8-4.7-2.1-6.7s-3.2-3.5-5.6-4.5c-2.4-1-5.1-1.5-8.1-1.5-2.8 0-5.3.5-7.6 1.4-2.3 1-4.2 2.4-5.4 4.3-1.2 1.9-1.9 3.9-1.9 6.1 0 1.7.4 3.4 1.2 4.9l.3.5h11.8c-2.3-.9-3.9-1.7-5.2-2.9zm13.3-6.2zM22.7 20.3zM13 34.1h46.1v3.4H13z"/></symbol><symbol id="trumbowyg-strong" viewBox="0 0 72 72"><path d="M51.1 37.8c-1.1-1.4-2.5-2.5-4.2-3.3 1.2-.8 2.1-1.8 2.8-3 1-1.6 1.5-3.5 1.5-5.3 0-2-.6-4-1.7-5.8-1.1-1.8-2.8-3.2-4.8-4.1-2-.9-4.6-1.3-7.8-1.3h-16v42h16.3c2.6 0 4.8-.2 6.7-.7 1.9-.5 3.4-1.2 4.7-2.1 1.3-1 2.4-2.4 3.2-4.1.9-1.7 1.3-3.6 1.3-5.7.2-2.5-.5-4.7-2-6.6zM40.8 50.2c-.6.1-1.8.2-3.4.2h-9V38.5h8.3c2.5 0 4.4.2 5.6.6 1.2.4 2 1 2.7 2 .6.9 1 2 1 3.3 0 1.1-.2 2.1-.7 2.9-.5.9-1 1.5-1.7 1.9-.8.4-1.7.8-2.8 1zm2.6-20.4c-.5.7-1.3 1.3-2.5 1.6-.8.3-2.5.4-4.8.4h-7.7V21.6h7.1c1.4 0 2.6 0 3.6.1s1.7.2 2.2.4c1 .3 1.7.8 2.2 1.7.5.9.8 1.8.8 3-.1 1.3-.4 2.2-.9 3z"/></symbol><symbol id="trumbowyg-subscript" viewBox="0 0 72 72"><path d="M32 15h7.8L56 57.1h-7.9L44.3 46H27.4l-4 11.1h-7.6L32 15zm-2.5 25.4h12.9L36 22.3h-.2l-6.3 18.1zM58.7 59.9c.6-1.4 2-2.8 4.1-4.4 1.9-1.3 3.1-2.3 3.7-2.9.8-.9 1.3-1.9 1.3-3 0-.9-.2-1.6-.7-2.2-.5-.6-1.2-.9-2.1-.9-1.2 0-2.1.5-2.5 1.4-.3.5-.4 1.4-.5 2.5h-4c.1-1.8.4-3.2 1-4.3 1.1-2.1 3-3.1 5.8-3.1 2.2 0 3.9.6 5.2 1.8 1.3 1.2 1.9 2.8 1.9 4.8 0 1.5-.5 2.9-1.4 4.1-.6.8-1.6 1.7-3 2.6L66 57.7c-1 .7-1.7 1.2-2.1 1.6-.4.3-.7.7-1 1.1H72V64H57.8c0-1.5.3-2.8.9-4.1z"/></symbol><symbol id="trumbowyg-superscript" viewBox="0 0 72 72"><path d="M32 15h7.8L56 57.1h-7.9l-4-11.1H27.4l-4 11.1h-7.6L32 15zm-2.5 25.4h12.9L36 22.3h-.2l-6.3 18.1zM49.6 28.8c.5-1.1 1.6-2.3 3.4-3.6 1.5-1.1 2.5-1.9 3-2.4.7-.7 1-1.6 1-2.4 0-.7-.2-1.3-.6-1.8-.4-.5-1-.7-1.7-.7-1 0-1.7.4-2.1 1.1-.2.4-.3 1.1-.4 2.1H49c.1-1.5.3-2.6.8-3.5.9-1.7 2.5-2.6 4.8-2.6 1.8 0 3.2.5 4.3 1.5 1.1 1 1.6 2.3 1.6 4 0 1.3-.4 2.4-1.1 3.4-.5.7-1.3 1.4-2.4 2.2l-1.3 1c-.8.6-1.4 1-1.7 1.3-.3.3-.6.6-.8.9h7.4v3H48.8c0-1.3.3-2.4.8-3.5z"/></symbol><symbol id="trumbowyg-table" viewBox="0 0 72 72"><path d="M25.686 51.38v-6.347q0-.462-.297-.76-.298-.297-.761-.297H14.04q-.463 0-.761.297-.298.298-.298.76v6.346q0 .463.298.76.298.298.76.298h10.589q.463 0 .76-.298.298-.297.298-.76zm0-12.692v-6.346q0-.463-.297-.76-.298-.298-.761-.298H14.04q-.463 0-.761.298-.298.297-.298.76v6.346q0 .462.298.76.298.297.76.297h10.589q.463 0 .76-.297.298-.298.298-.76zm16.94 12.691v-6.346q0-.462-.297-.76-.298-.297-.761-.297H30.98q-.463 0-.76.297-.299.298-.299.76v6.346q0 .463.298.76.298.298.761.298h10.588q.463 0 .76-.298.299-.297.299-.76zm-16.94-25.383v-6.345q0-.463-.297-.76-.298-.298-.761-.298H14.04q-.463 0-.761.297-.298.298-.298.76v6.346q0 .463.298.76.298.298.76.298h10.589q.463 0 .76-.298.298-.297.298-.76zm16.94 12.692v-6.346q0-.463-.297-.76-.298-.298-.761-.298H30.98q-.463 0-.76.298-.299.297-.299.76v6.346q0 .462.298.76.298.297.761.297h10.588q.463 0 .76-.297.299-.298.299-.76zm16.94 12.691v-6.346q0-.462-.297-.76-.298-.297-.76-.297H47.92q-.463 0-.76.297-.298.298-.298.76v6.346q0 .463.297.76.298.298.761.298h10.588q.463 0 .761-.298.298-.297.298-.76zm-16.94-25.383v-6.345q0-.463-.297-.76-.298-.298-.761-.298H30.98q-.463 0-.76.297-.299.298-.299.76v6.346q0 .463.298.76.298.298.761.298h10.588q.463 0 .76-.298.299-.297.299-.76zm16.94 12.692v-6.346q0-.463-.297-.76-.298-.298-.76-.298H47.92q-.463 0-.76.298-.298.297-.298.76v6.346q0 .462.297.76.298.297.761.297h10.588q.463 0 .761-.297.298-.298.298-.76zm0-12.692v-6.345q0-.463-.297-.76-.298-.298-.76-.298H47.92q-.463 0-.76.297-.298.298-.298.76v6.346q0 .463.297.76.298.298.761.298h10.588q.463 0 .761-.298.298-.297.298-.76zm4.236-10.576v35.96q0 2.18-1.555 3.734-1.555 1.553-3.739 1.553H14.04q-2.184 0-3.739-1.553-1.555-1.553-1.555-3.735V15.42q0-2.181 1.555-3.735 1.555-1.553 3.739-1.553h44.468q2.184 0 3.739 1.553 1.555 1.554 1.555 3.735z"/></symbol><symbol id="trumbowyg-underline" viewBox="0 0 72 72"><path d="M36 35zM15.2 55.9h41.6V59H15.2zM21.1 13.9h6.4v21.2c0 1.2.1 2.5.2 3.7.1 1.3.5 2.4 1 3.4.6 1 1.4 1.8 2.6 2.5 1.1.6 2.7 1 4.8 1 2.1 0 3.7-.3 4.8-1 1.1-.6 2-1.5 2.6-2.5.6-1 .9-2.1 1-3.4.1-1.3.2-2.5.2-3.7V13.9H51v23.3c0 2.3-.4 4.4-1.1 6.1-.7 1.7-1.7 3.2-3 4.4-1.3 1.2-2.9 2-4.7 2.6-1.8.6-3.9.9-6.1.9-2.2 0-4.3-.3-6.1-.9-1.8-.6-3.4-1.5-4.7-2.6-1.3-1.2-2.3-2.6-3-4.4-.7-1.7-1.1-3.8-1.1-6.1V13.9z"/></symbol><symbol id="trumbowyg-undo" viewBox="0 0 72 72"><path d="M61.2 51.2c0-5.1-2.1-9.7-5.4-13.1-3.3-3.3-8-5.4-13.1-5.4H26.1v-12L10.8 36l15.3 15.3V39.1h16.7c3.3 0 6.4 1.3 8.5 3.5 2.2 2.2 3.5 5.2 3.5 8.5h6.4z"/></symbol><symbol id="trumbowyg-unlink" viewBox="0 0 72 72"><path d="M30.9 49.1l-6.7 6.7c-.8.8-1.6.9-2.1.9s-1.4-.1-2.1-.9l-5.2-5.2c-1.1-1.1-1.1-3.1 0-4.2l6.1-6.1.2-.2 6.5-6.5c-1.2-.6-2.5-.9-3.8-.9-2.3 0-4.6.9-6.3 2.6L10.8 42c-3.5 3.5-3.5 9.2 0 12.7l5.2 5.2c1.7 1.7 4 2.6 6.3 2.6s4.6-.9 6.3-2.6l6.7-6.7C38 50.5 38.6 46.3 37 43l-6.1 6.1zM38.5 22.7l6.7-6.7c.8-.8 1.6-.9 2.1-.9s1.4.1 2.1.9l5.2 5.2c1.1 1.1 1.1 3.1 0 4.2l-6.1 6.1-.2.2-6.5 6.5c1.2.6 2.5.9 3.8.9 2.3 0 4.6-.9 6.3-2.6l6.7-6.7c3.5-3.5 3.5-9.2 0-12.7l-5.2-5.2c-1.7-1.7-4-2.6-6.3-2.6s-4.6.9-6.3 2.6l-6.7 6.7c-2.7 2.7-3.3 6.9-1.7 10.2l6.1-6.1z"/><path d="M44.1 30.7c.2-.2.4-.6.4-.9 0-.3-.1-.6-.4-.9l-2.3-2.3c-.2-.2-.6-.4-.9-.4-.3 0-.6.1-.9.4L25.8 40.8c-.2.2-.4.6-.4.9 0 .3.1.6.4.9l2.3 2.3c.2.2.6.4.9.4.3 0 .6-.1.9-.4l14.2-14.2zM41.3 55.8v-5h22.2v5H41.3z"/></symbol><symbol id="trumbowyg-unordered-list" viewBox="0 0 72 72"><path d="M27 14h36v8H27zM27 50h36v8H27zM9 50h9v8H9zM9 32h9v8H9zM9 14h9v8H9zM27 32h36v8H27z"/></symbol><symbol id="trumbowyg-view-html" viewBox="0 0 72 72"><path fill="none" stroke="currentColor" stroke-width="8" stroke-miterlimit="10" d="M26.9 17.9L9 36.2 26.9 54M45 54l17.9-18.3L45 17.9"/></symbol><symbol id="trumbowyg-base64" viewBox="0 0 72 72"><path d="M64 17v38H8V17h56m8-8H0v54h72V9z"/><path d="M29.9 28.9c-.5-.5-1.1-.8-1.8-.8s-1.4.2-1.9.7c-.5.4-.9 1-1.2 1.6-.3.6-.5 1.3-.6 2.1-.1.7-.2 1.4-.2 1.9l.1.1c.6-.8 1.2-1.4 2-1.8.8-.4 1.7-.5 2.7-.5.9 0 1.8.2 2.6.6.8.4 1.6.9 2.2 1.5.6.6 1 1.3 1.2 2.2.3.8.4 1.6.4 2.5 0 1.1-.2 2.1-.5 3-.3.9-.8 1.7-1.5 2.4-.6.7-1.4 1.2-2.3 1.6-.9.4-1.9.6-3 .6-1.6 0-2.8-.3-3.9-.9-1-.6-1.8-1.4-2.5-2.4-.6-1-1-2.1-1.3-3.4-.2-1.3-.4-2.6-.4-3.9 0-1.3.1-2.6.4-3.8.3-1.3.8-2.4 1.4-3.5.7-1 1.5-1.9 2.5-2.5 1-.6 2.3-1 3.8-1 .9 0 1.7.1 2.5.4.8.3 1.4.6 2 1.1.6.5 1.1 1.1 1.4 1.8.4.7.6 1.5.7 2.5h-4c0-1-.3-1.6-.8-2.1zm-3.5 6.8c-.4.2-.8.5-1 .8-.3.4-.5.8-.6 1.2-.1.5-.2 1-.2 1.5s.1.9.2 1.4c.1.5.4.9.6 1.2.3.4.6.7 1 .9.4.2.9.3 1.4.3.5 0 1-.1 1.3-.3.4-.2.7-.5 1-.9.3-.4.5-.8.6-1.2.1-.5.2-.9.2-1.4 0-.5-.1-1-.2-1.4-.1-.5-.3-.9-.6-1.2-.3-.4-.6-.7-1-.9-.4-.2-.9-.3-1.4-.3-.4 0-.9.1-1.3.3zM36.3 41.3v-3.8l9-12.1H49v12.4h2.7v3.5H49v4.8h-4v-4.8h-8.7zM45 30.7l-5.3 7.2h5.4l-.1-7.2z"/></symbol><symbol id="trumbowyg-back-color" viewBox="0 0 72 72"><path d="M36.5 22.3l-6.3 18.1H43l-6.3-18.1z"/><path d="M9 8.9v54.2h54.1V8.9H9zm39.9 48.2L45 46H28.2l-3.9 11.1h-7.6L32.8 15h7.8l16.2 42.1h-7.9z"/></symbol><symbol id="trumbowyg-fore-color" viewBox="0 0 72 72"><path d="M32 15h7.8L56 57.1h-7.9l-4-11.1H27.4l-4 11.1h-7.6L32 15zm-2.5 25.4h12.9L36 22.3h-.2l-6.3 18.1z"/></symbol><symbol id="trumbowyg-emoji" viewBox="0 0 72 72"><path d="M36.05 9C21.09 9 8.949 21.141 8.949 36.101c0 14.96 12.141 27.101 27.101 27.101 14.96 0 27.101-12.141 27.101-27.101S51.01 9 36.05 9zm9.757 15.095c2.651 0 4.418 1.767 4.418 4.418s-1.767 4.418-4.418 4.418-4.418-1.767-4.418-4.418 1.767-4.418 4.418-4.418zm-19.479 0c2.651 0 4.418 1.767 4.418 4.418s-1.767 4.418-4.418 4.418-4.418-1.767-4.418-4.418 1.767-4.418 4.418-4.418zm9.722 30.436c-14.093 0-16.261-13.009-16.261-13.009h32.522S50.143 54.531 36.05 54.531z"/></symbol><symbol id="trumbowyg-insert-audio" viewBox="0 0 8 8"><path d="M3.344 0L2 2H0v4h2l1.344 2H4V0h-.656zM5 1v1c.152 0 .313.026.469.063H5.5c.86.215 1.5.995 1.5 1.938a1.99 1.99 0 0 1-2 2.001v1a2.988 2.988 0 0 0 3-3 2.988 2.988 0 0 0-3-3zm0 2v2l.25-.031C5.683 4.851 6 4.462 6 4c0-.446-.325-.819-.75-.938v-.031h-.031L5 3z"/></symbol><symbol id="trumbowyg-mathml" viewBox="0 0 445.878 445.878"><path d="M426.024 86.447H209.705l-84.911 298.911c-2.568 7.967-9.854 13.482-18.22 13.771-.236 0-.464.006-.688.006a19.868 19.868 0 0 1-18.436-12.478l-34.714-86.782H19.851C8.884 299.876 0 290.986 0 280.022c0-10.965 8.893-19.854 19.851-19.854H66.18a19.862 19.862 0 0 1 18.436 12.483l19.237 48.09 72.472-260.218a19.855 19.855 0 0 1 18.903-13.781h230.798c10.97 0 19.854 8.89 19.854 19.851s-8.892 19.854-19.856 19.854zm10.699 266.78l-78.259-87.904 74.576-82.783c1.318-1.454 1.638-3.547.857-5.341a4.977 4.977 0 0 0-4.54-2.946h-47.18a4.995 4.995 0 0 0-3.759 1.72l-50.059 58.047-49.674-58.029a4.95 4.95 0 0 0-3.771-1.738H225.58a4.947 4.947 0 0 0-4.521 2.929 4.939 4.939 0 0 0 .824 5.332l73.743 82.81-77.641 87.923a4.977 4.977 0 0 0-.813 5.325 4.978 4.978 0 0 0 4.528 2.92h48.9c1.472 0 2.867-.65 3.807-1.785l51.819-62.181 53.05 62.229a4.972 4.972 0 0 0 3.782 1.743h49.97a4.938 4.938 0 0 0 4.527-2.926 4.966 4.966 0 0 0-.832-5.345z"/></symbol><symbol id="trumbowyg-mention" viewBox="0 0 128 128"><path fill-rule="evenodd" d="M73.309 62.5c-1.53 9.86-8.16 17.85-14.45 17.85-5.61 0-8.5-4.08-8.5-10.54 0-13.089 8.84-24.139 20.06-24.139 2.21 0 3.91.34 5.27.68L73.309 62.5zm14.45 44.2c-6.8 3.57-15.98 5.44-24.65 5.44-25.329 0-43.519-16.15-43.519-44.54 0-32.469 22.78-52.869 48.789-52.869 26.35 0 40.63 17.17 40.63 39.27 0 19.549-9.18 28.899-16.49 28.729-4.76-.17-5.95-4.76-4.25-14.79l5.1-31.449c-4.25-2.38-12.75-4.25-20.23-4.25-24.48 0-39.779 18.87-39.779 39.609 0 13.94 7.99 22.1 19.039 22.1 9.01 0 16.66-4.42 21.93-13.09h.34c.85 9.01 6.63 13.09 14.62 13.09 18.36 0 32.3-15.64 32.3-40.459 0-28.56-21.42-49.13-51.34-49.13C31.83 4.361 6.67 34.451 6.67 69.13c0 33.32 24.82 53.55 53.039 53.55 12.07 0 20.91-1.53 31.11-6.12l-3.06-9.86z"/></symbol><symbol id="trumbowyg-noembed" viewBox="0 0 72 72"><path d="M31.5 33.6V25l11 11-11 11v-8.8z"/><path d="M64 17v38H8V17h56m8-8H0v54h72V9z"/></symbol><symbol id="trumbowyg-preformatted" viewBox="0 0 72 72"><path d="M10.3 33.5c.4 0 .9-.1 1.5-.2s1.2-.3 1.8-.7c.6-.3 1.1-.8 1.5-1.3.4-.5.6-1.3.6-2.1V17.1c0-1.4.3-2.6.8-3.6s1.2-1.9 2-2.5c.8-.7 1.6-1.2 2.5-1.5.9-.3 1.6-.5 2.2-.5h5.3v5.3h-3.2c-.7 0-1.3.1-1.8.4-.4.3-.8.6-1 1-.2.4-.4.9-.4 1.3-.1.5-.1.9-.1 1.4v11.4c0 1.2-.2 2.1-.7 2.9-.5.8-1 1.4-1.7 1.8-.6.4-1.3.8-2 1-.7.2-1.3.3-1.7.4v.1c.5 0 1 .1 1.7.3.7.2 1.3.5 2 .9.6.5 1.2 1.1 1.7 1.9.5.8.7 2 .7 3.4v11.1c0 .4 0 .9.1 1.4.1.5.2.9.4 1.3s.6.7 1 1c.4.3 1 .4 1.8.4h3.2V63h-5.3c-.6 0-1.4-.2-2.2-.5-.9-.3-1.7-.8-2.5-1.5s-1.4-1.5-2-2.5c-.5-1-.8-2.2-.8-3.6V43.5c0-.9-.2-1.7-.6-2.3-.4-.6-.9-1.1-1.5-1.5-.6-.4-1.2-.6-1.8-.7-.6-.1-1.1-.2-1.5-.2v-5.3zM61.8 38.7c-.4 0-1 .1-1.6.2-.6.1-1.2.4-1.8.7-.6.3-1.1.7-1.5 1.3-.4.5-.6 1.3-.6 2.1v12.1c0 1.4-.3 2.6-.8 3.6s-1.2 1.9-2 2.5c-.8.7-1.6 1.2-2.5 1.5-.9.3-1.6.5-2.2.5h-5.3v-5.3h3.2c.7 0 1.3-.1 1.8-.4.4-.3.8-.6 1-1 .2-.4.4-.9.4-1.3.1-.5.1-.9.1-1.4V42.3c0-1.2.2-2.1.7-2.9.5-.8 1-1.4 1.7-1.8.6-.4 1.3-.8 2-1 .7-.2 1.3-.3 1.7-.4v-.1c-.5 0-1-.1-1.7-.3-.7-.2-1.3-.5-2-.9-.6-.4-1.2-1.1-1.7-1.9-.5-.8-.7-2-.7-3.4V18.5c0-.4 0-.9-.1-1.4-.1-.5-.2-.9-.4-1.3s-.6-.7-1-1c-.4-.3-1-.4-1.8-.4h-3.2V9.1h5.3c.6 0 1.4.2 2.2.5.9.3 1.7.8 2.5 1.5s1.4 1.5 2 2.5c.5 1 .8 2.2.8 3.6v11.6c0 .9.2 1.7.6 2.3.4.6.9 1.1 1.5 1.5.6.4 1.2.6 1.8.7.6.1 1.2.2 1.6.2v5.2z"/></symbol><symbol id="trumbowyg-ruby" viewBox="0 0 72 72"><path d="M16.499 24.477h8.018L41.08 67.5H33l-4.04-11.361H11.804L7.764 67.5H0l16.499-43.023zm-2.65 25.907h13.127l-6.438-18.497h-.177l-6.512 18.497zM65.053 16.685c-6.316 1.178-12.025 1.98-17.126 2.408a362.385 362.385 0 0 0-.965 5.833c-.25 1.57-.679 3.907-1.286 7.013 3.033-1.963 5.852-3.266 8.458-3.907 2.639-.642 4.905-.891 6.797-.75 1.891.108 3.746.661 5.566 1.661 1.82.964 3.264 2.408 4.334 4.334 1.104 1.893 1.427 4.088.965 6.584-.466 2.461-1.554 4.494-3.265 6.101-1.679 1.605-3.658 2.783-5.941 3.532-2.283.785-4.853 1.251-7.707 1.391-2.819.144-5.906.161-9.259.056 0-1.642-.287-3.212-.857-4.71l.108-.59c2.711.5 5.246.768 7.601.802 2.39 0 4.529-.195 6.421-.589 1.927-.393 3.605-1.069 5.031-2.031 1.427-.965 2.319-2.319 2.676-4.067.394-1.75.269-3.229-.373-4.443-.644-1.249-1.446-2.213-2.408-2.891-.929-.68-2.161-1.034-3.693-1.071-1.536-.072-3.265.089-5.192.482-1.927.391-3.82 1.14-5.672 2.248a24.308 24.308 0 0 0-4.978 3.907l-4.872-1.981c1.463-5.031 2.355-8.597 2.677-10.703.321-2.105.642-4.067.963-5.887-3.961.25-7.154.411-9.58.481-.215-1.927-.52-3.534-.91-4.817l.32-.32c3.604.32 7.225.446 10.865.375.214-1.355.481-3.103.804-5.245.354-2.175.407-3.621.16-4.336.034-.784.374-1.017 1.017-.695l5.085.749c.428.251.444.573.055.964l-.857.91c-.537 2.89-.981 5.352-1.338 7.385 4.279-.427 9.312-1.393 15.092-2.89l1.284 4.707"/></symbol><symbol id="trumbowyg-upload" viewBox="0 0 72 72"><path d="M64 27v28H8V27H0v36h72V27h-8z"/><path d="M32.1 6.7h8v33.6h-8z"/><path d="M48 35.9L36 49.6 24 36h24z"/></symbol></svg> |
| \ No newline at end of file | |
public/javascripts/app.js
+5
-1
| @@ | @@ -1,6 +1,7 @@ |
| + | //= require vendor/autosize |
| + | //= require vendor/foundation |
| //= require vendor/jquery.sticky | |
| //= require vendor/what-input | |
| - | //= require vendor/foundation |
| $(document).foundation(); | |
| // $(".top-bar").sticky({zIndex:10}); | |
| @@ | @@ -11,3 +12,6 @@ $('nav#top-nav > ul ul').addClass('menu') |
| $('header[data-background-url]').each(function() { | |
| $(this).css('background-image', 'url("' + $(this).data('background-url') + '")') | |
| }) | |
| + | |
| + | autosize($('textarea.autosize')); |
| + | |
public/javascripts/vendor/autosize.js
+292
-0
| @@ | @@ -0,0 +1,292 @@ |
| + | /*! |
| + | Autosize 4.0.0 |
| + | license: MIT |
| + | http://www.jacklmoore.com/autosize |
| + | */ |
| + | (function (global, factory) { |
| + | if (typeof define === 'function' && define.amd) { |
| + | define(['exports', 'module'], factory); |
| + | } else if (typeof exports !== 'undefined' && typeof module !== 'undefined') { |
| + | factory(exports, module); |
| + | } else { |
| + | var mod = { |
| + | exports: {} |
| + | }; |
| + | factory(mod.exports, mod); |
| + | global.autosize = mod.exports; |
| + | } |
| + | })(this, function (exports, module) { |
| + | 'use strict'; |
| + | |
| + | var map = typeof Map === "function" ? new Map() : (function () { |
| + | var keys = []; |
| + | var values = []; |
| + | |
| + | return { |
| + | has: function has(key) { |
| + | return keys.indexOf(key) > -1; |
| + | }, |
| + | get: function get(key) { |
| + | return values[keys.indexOf(key)]; |
| + | }, |
| + | set: function set(key, value) { |
| + | if (keys.indexOf(key) === -1) { |
| + | keys.push(key); |
| + | values.push(value); |
| + | } |
| + | }, |
| + | 'delete': function _delete(key) { |
| + | var index = keys.indexOf(key); |
| + | if (index > -1) { |
| + | keys.splice(index, 1); |
| + | values.splice(index, 1); |
| + | } |
| + | } |
| + | }; |
| + | })(); |
| + | |
| + | var createEvent = function createEvent(name) { |
| + | return new Event(name, { bubbles: true }); |
| + | }; |
| + | try { |
| + | new Event('test'); |
| + | } catch (e) { |
| + | // IE does not support `new Event()` |
| + | createEvent = function (name) { |
| + | var evt = document.createEvent('Event'); |
| + | evt.initEvent(name, true, false); |
| + | return evt; |
| + | }; |
| + | } |
| + | |
| + | function assign(ta) { |
| + | if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) return; |
| + | |
| + | var heightOffset = null; |
| + | var clientWidth = ta.clientWidth; |
| + | var cachedHeight = null; |
| + | |
| + | function init() { |
| + | var style = window.getComputedStyle(ta, null); |
| + | |
| + | if (style.resize === 'vertical') { |
| + | ta.style.resize = 'none'; |
| + | } else if (style.resize === 'both') { |
| + | ta.style.resize = 'horizontal'; |
| + | } |
| + | |
| + | if (style.boxSizing === 'content-box') { |
| + | heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom)); |
| + | } else { |
| + | heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth); |
| + | } |
| + | // Fix when a textarea is not on document body and heightOffset is Not a Number |
| + | if (isNaN(heightOffset)) { |
| + | heightOffset = 0; |
| + | } |
| + | |
| + | update(); |
| + | } |
| + | |
| + | function changeOverflow(value) { |
| + | { |
| + | // Chrome/Safari-specific fix: |
| + | // When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space |
| + | // made available by removing the scrollbar. The following forces the necessary text reflow. |
| + | var width = ta.style.width; |
| + | ta.style.width = '0px'; |
| + | // Force reflow: |
| + | /* jshint ignore:start */ |
| + | ta.offsetWidth; |
| + | /* jshint ignore:end */ |
| + | ta.style.width = width; |
| + | } |
| + | |
| + | ta.style.overflowY = value; |
| + | } |
| + | |
| + | function getParentOverflows(el) { |
| + | var arr = []; |
| + | |
| + | while (el && el.parentNode && el.parentNode instanceof Element) { |
| + | if (el.parentNode.scrollTop) { |
| + | arr.push({ |
| + | node: el.parentNode, |
| + | scrollTop: el.parentNode.scrollTop |
| + | }); |
| + | } |
| + | el = el.parentNode; |
| + | } |
| + | |
| + | return arr; |
| + | } |
| + | |
| + | function resize() { |
| + | var originalHeight = ta.style.height; |
| + | var overflows = getParentOverflows(ta); |
| + | var docTop = document.documentElement && document.documentElement.scrollTop; // Needed for Mobile IE (ticket #240) |
| + | |
| + | ta.style.height = ''; |
| + | |
| + | var endHeight = ta.scrollHeight + heightOffset; |
| + | |
| + | if (ta.scrollHeight === 0) { |
| + | // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM. |
| + | ta.style.height = originalHeight; |
| + | return; |
| + | } |
| + | |
| + | ta.style.height = endHeight + 'px'; |
| + | |
| + | // used to check if an update is actually necessary on window.resize |
| + | clientWidth = ta.clientWidth; |
| + | |
| + | // prevents scroll-position jumping |
| + | overflows.forEach(function (el) { |
| + | el.node.scrollTop = el.scrollTop; |
| + | }); |
| + | |
| + | if (docTop) { |
| + | document.documentElement.scrollTop = docTop; |
| + | } |
| + | } |
| + | |
| + | function update() { |
| + | resize(); |
| + | |
| + | var styleHeight = Math.round(parseFloat(ta.style.height)); |
| + | var computed = window.getComputedStyle(ta, null); |
| + | |
| + | // Using offsetHeight as a replacement for computed.height in IE, because IE does not account use of border-box |
| + | var actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(computed.height)) : ta.offsetHeight; |
| + | |
| + | // The actual height not matching the style height (set via the resize method) indicates that |
| + | // the max-height has been exceeded, in which case the overflow should be allowed. |
| + | if (actualHeight !== styleHeight) { |
| + | if (computed.overflowY === 'hidden') { |
| + | changeOverflow('scroll'); |
| + | resize(); |
| + | actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight; |
| + | } |
| + | } else { |
| + | // Normally keep overflow set to hidden, to avoid flash of scrollbar as the textarea expands. |
| + | if (computed.overflowY !== 'hidden') { |
| + | changeOverflow('hidden'); |
| + | resize(); |
| + | actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight; |
| + | } |
| + | } |
| + | |
| + | if (cachedHeight !== actualHeight) { |
| + | cachedHeight = actualHeight; |
| + | var evt = createEvent('autosize:resized'); |
| + | try { |
| + | ta.dispatchEvent(evt); |
| + | } catch (err) { |
| + | // Firefox will throw an error on dispatchEvent for a detached element |
| + | // https://bugzilla.mozilla.org/show_bug.cgi?id=889376 |
| + | } |
| + | } |
| + | } |
| + | |
| + | var pageResize = function pageResize() { |
| + | if (ta.clientWidth !== clientWidth) { |
| + | update(); |
| + | } |
| + | }; |
| + | |
| + | var destroy = (function (style) { |
| + | window.removeEventListener('resize', pageResize, false); |
| + | ta.removeEventListener('input', update, false); |
| + | ta.removeEventListener('keyup', update, false); |
| + | ta.removeEventListener('autosize:destroy', destroy, false); |
| + | ta.removeEventListener('autosize:update', update, false); |
| + | |
| + | Object.keys(style).forEach(function (key) { |
| + | ta.style[key] = style[key]; |
| + | }); |
| + | |
| + | map['delete'](ta); |
| + | }).bind(ta, { |
| + | height: ta.style.height, |
| + | resize: ta.style.resize, |
| + | overflowY: ta.style.overflowY, |
| + | overflowX: ta.style.overflowX, |
| + | wordWrap: ta.style.wordWrap |
| + | }); |
| + | |
| + | ta.addEventListener('autosize:destroy', destroy, false); |
| + | |
| + | // IE9 does not fire onpropertychange or oninput for deletions, |
| + | // so binding to onkeyup to catch most of those events. |
| + | // There is no way that I know of to detect something like 'cut' in IE9. |
| + | if ('onpropertychange' in ta && 'oninput' in ta) { |
| + | ta.addEventListener('keyup', update, false); |
| + | } |
| + | |
| + | window.addEventListener('resize', pageResize, false); |
| + | ta.addEventListener('input', update, false); |
| + | ta.addEventListener('autosize:update', update, false); |
| + | ta.style.overflowX = 'hidden'; |
| + | ta.style.wordWrap = 'break-word'; |
| + | |
| + | map.set(ta, { |
| + | destroy: destroy, |
| + | update: update |
| + | }); |
| + | |
| + | init(); |
| + | } |
| + | |
| + | function destroy(ta) { |
| + | var methods = map.get(ta); |
| + | if (methods) { |
| + | methods.destroy(); |
| + | } |
| + | } |
| + | |
| + | function update(ta) { |
| + | var methods = map.get(ta); |
| + | if (methods) { |
| + | methods.update(); |
| + | } |
| + | } |
| + | |
| + | var autosize = null; |
| + | |
| + | // Do nothing in Node.js environment and IE8 (or lower) |
| + | if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') { |
| + | autosize = function (el) { |
| + | return el; |
| + | }; |
| + | autosize.destroy = function (el) { |
| + | return el; |
| + | }; |
| + | autosize.update = function (el) { |
| + | return el; |
| + | }; |
| + | } else { |
| + | autosize = function (el, options) { |
| + | if (el) { |
| + | Array.prototype.forEach.call(el.length ? el : [el], function (x) { |
| + | return assign(x, options); |
| + | }); |
| + | } |
| + | return el; |
| + | }; |
| + | autosize.destroy = function (el) { |
| + | if (el) { |
| + | Array.prototype.forEach.call(el.length ? el : [el], destroy); |
| + | } |
| + | return el; |
| + | }; |
| + | autosize.update = function (el) { |
| + | if (el) { |
| + | Array.prototype.forEach.call(el.length ? el : [el], update); |
| + | } |
| + | return el; |
| + | }; |
| + | } |
| + | |
| + | module.exports = autosize; |
| + | }); |
| \ No newline at end of file | |
public/javascripts/vendor/trumbowyg.js
+1738
-0
| @@ | @@ -0,0 +1,1738 @@ |
| + | /** |
| + | * Trumbowyg v2.9.4 - A lightweight WYSIWYG editor |
| + | * Trumbowyg core file |
| + | * ------------------------ |
| + | * @link http://alex-d.github.io/Trumbowyg |
| + | * @license MIT |
| + | * @author Alexandre Demode (Alex-D) |
| + | * Twitter : @AlexandreDemode |
| + | * Website : alex-d.fr |
| + | */ |
| + | |
| + | jQuery.trumbowyg = { |
| + | langs: { |
| + | en: { |
| + | viewHTML: 'View HTML', |
| + | |
| + | undo: 'Undo', |
| + | redo: 'Redo', |
| + | |
| + | formatting: 'Formatting', |
| + | p: 'Paragraph', |
| + | blockquote: 'Quote', |
| + | code: 'Code', |
| + | header: 'Header', |
| + | |
| + | bold: 'Bold', |
| + | italic: 'Italic', |
| + | strikethrough: 'Stroke', |
| + | underline: 'Underline', |
| + | |
| + | strong: 'Strong', |
| + | em: 'Emphasis', |
| + | del: 'Deleted', |
| + | |
| + | superscript: 'Superscript', |
| + | subscript: 'Subscript', |
| + | |
| + | unorderedList: 'Unordered list', |
| + | orderedList: 'Ordered list', |
| + | |
| + | insertImage: 'Insert Image', |
| + | link: 'Link', |
| + | createLink: 'Insert link', |
| + | unlink: 'Remove link', |
| + | |
| + | justifyLeft: 'Align Left', |
| + | justifyCenter: 'Align Center', |
| + | justifyRight: 'Align Right', |
| + | justifyFull: 'Align Justify', |
| + | |
| + | horizontalRule: 'Insert horizontal rule', |
| + | removeformat: 'Remove format', |
| + | |
| + | fullscreen: 'Fullscreen', |
| + | |
| + | close: 'Close', |
| + | |
| + | submit: 'Confirm', |
| + | reset: 'Cancel', |
| + | |
| + | required: 'Required', |
| + | description: 'Description', |
| + | title: 'Title', |
| + | text: 'Text', |
| + | target: 'Target', |
| + | width: 'Width' |
| + | } |
| + | }, |
| + | |
| + | // Plugins |
| + | plugins: {}, |
| + | |
| + | // SVG Path globally |
| + | svgPath: null, |
| + | |
| + | hideButtonTexts: null |
| + | }; |
| + | |
| + | // Makes default options read-only |
| + | Object.defineProperty(jQuery.trumbowyg, 'defaultOptions', { |
| + | value: { |
| + | lang: 'en', |
| + | |
| + | fixedBtnPane: false, |
| + | fixedFullWidth: false, |
| + | autogrow: false, |
| + | autogrowOnEnter: false, |
| + | imageWidthModalEdit: false, |
| + | |
| + | prefix: 'trumbowyg-', |
| + | |
| + | semantic: true, |
| + | resetCss: false, |
| + | removeformatPasted: false, |
| + | tagsToRemove: [], |
| + | btns: [ |
| + | ['viewHTML'], |
| + | ['undo', 'redo'], // Only supported in Blink browsers |
| + | ['formatting'], |
| + | ['strong', 'em', 'del'], |
| + | ['superscript', 'subscript'], |
| + | ['link'], |
| + | ['insertImage'], |
| + | ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'], |
| + | ['unorderedList', 'orderedList'], |
| + | ['horizontalRule'], |
| + | ['removeformat'], |
| + | ['fullscreen'] |
| + | ], |
| + | // For custom button definitions |
| + | btnsDef: {}, |
| + | |
| + | inlineElementsSelector: 'a,abbr,acronym,b,caption,cite,code,col,dfn,dir,dt,dd,em,font,hr,i,kbd,li,q,span,strikeout,strong,sub,sup,u', |
| + | |
| + | pasteHandlers: [], |
| + | |
| + | // imgDblClickHandler: default is defined in constructor |
| + | |
| + | plugins: {} |
| + | }, |
| + | writable: false, |
| + | enumerable: true, |
| + | configurable: false |
| + | }); |
| + | |
| + | |
| + | (function (navigator, window, document, $) { |
| + | 'use strict'; |
| + | |
| + | var CONFIRM_EVENT = 'tbwconfirm', |
| + | CANCEL_EVENT = 'tbwcancel'; |
| + | |
| + | $.fn.trumbowyg = function (options, params) { |
| + | var trumbowygDataName = 'trumbowyg'; |
| + | if (options === Object(options) || !options) { |
| + | return this.each(function () { |
| + | if (!$(this).data(trumbowygDataName)) { |
| + | $(this).data(trumbowygDataName, new Trumbowyg(this, options)); |
| + | } |
| + | }); |
| + | } |
| + | if (this.length === 1) { |
| + | try { |
| + | var t = $(this).data(trumbowygDataName); |
| + | switch (options) { |
| + | // Exec command |
| + | case 'execCmd': |
| + | return t.execCmd(params.cmd, params.param, params.forceCss); |
| + | |
| + | // Modal box |
| + | case 'openModal': |
| + | return t.openModal(params.title, params.content); |
| + | case 'closeModal': |
| + | return t.closeModal(); |
| + | case 'openModalInsert': |
| + | return t.openModalInsert(params.title, params.fields, params.callback); |
| + | |
| + | // Range |
| + | case 'saveRange': |
| + | return t.saveRange(); |
| + | case 'getRange': |
| + | return t.range; |
| + | case 'getRangeText': |
| + | return t.getRangeText(); |
| + | case 'restoreRange': |
| + | return t.restoreRange(); |
| + | |
| + | // Enable/disable |
| + | case 'enable': |
| + | return t.setDisabled(false); |
| + | case 'disable': |
| + | return t.setDisabled(true); |
| + | |
| + | // Toggle |
| + | case 'toggle': |
| + | return t.toggle(); |
| + | |
| + | // Destroy |
| + | case 'destroy': |
| + | return t.destroy(); |
| + | |
| + | // Empty |
| + | case 'empty': |
| + | return t.empty(); |
| + | |
| + | // HTML |
| + | case 'html': |
| + | return t.html(params); |
| + | } |
| + | } catch (c) { |
| + | } |
| + | } |
| + | |
| + | return false; |
| + | }; |
| + | |
| + | // @param: editorElem is the DOM element |
| + | var Trumbowyg = function (editorElem, options) { |
| + | var t = this, |
| + | trumbowygIconsId = 'trumbowyg-icons', |
| + | $trumbowyg = $.trumbowyg; |
| + | |
| + | // Get the document of the element. It use to makes the plugin |
| + | // compatible on iframes. |
| + | t.doc = editorElem.ownerDocument || document; |
| + | |
| + | // jQuery object of the editor |
| + | t.$ta = $(editorElem); // $ta : Textarea |
| + | t.$c = $(editorElem); // $c : creator |
| + | |
| + | options = options || {}; |
| + | |
| + | // Localization management |
| + | if (options.lang != null || $trumbowyg.langs[options.lang] != null) { |
| + | t.lang = $.extend(true, {}, $trumbowyg.langs.en, $trumbowyg.langs[options.lang]); |
| + | } else { |
| + | t.lang = $trumbowyg.langs.en; |
| + | } |
| + | |
| + | t.hideButtonTexts = $trumbowyg.hideButtonTexts != null ? $trumbowyg.hideButtonTexts : options.hideButtonTexts; |
| + | |
| + | // SVG path |
| + | var svgPathOption = $trumbowyg.svgPath != null ? $trumbowyg.svgPath : options.svgPath; |
| + | t.hasSvg = svgPathOption !== false; |
| + | t.svgPath = !!t.doc.querySelector('base') ? window.location.href.split('#')[0] : ''; |
| + | if ($('#' + trumbowygIconsId, t.doc).length === 0 && svgPathOption !== false) { |
| + | if (svgPathOption == null) { |
| + | // Hack to get svgPathOption based on trumbowyg.js path |
| + | var scriptElements = document.getElementsByTagName('script'); |
| + | for (var i = 0; i < scriptElements.length; i += 1) { |
| + | var source = scriptElements[i].src; |
| + | var matches = source.match('trumbowyg(\.min)?\.js'); |
| + | if (matches != null) { |
| + | svgPathOption = source.substring(0, source.indexOf(matches[0])) + '/ui/icons.svg'; |
| + | } |
| + | } |
| + | if (svgPathOption == null) { |
| + | console.warn('You must define svgPath: https://goo.gl/CfTY9U'); // jshint ignore:line |
| + | } |
| + | } |
| + | |
| + | var div = t.doc.createElement('div'); |
| + | div.id = trumbowygIconsId; |
| + | t.doc.body.insertBefore(div, t.doc.body.childNodes[0]); |
| + | $.ajax({ |
| + | async: true, |
| + | type: 'GET', |
| + | contentType: 'application/x-www-form-urlencoded; charset=UTF-8', |
| + | dataType: 'xml', |
| + | crossDomain: true, |
| + | url: svgPathOption, |
| + | data: null, |
| + | beforeSend: null, |
| + | complete: null, |
| + | success: function (data) { |
| + | div.innerHTML = new XMLSerializer().serializeToString(data.documentElement); |
| + | } |
| + | }); |
| + | } |
| + | |
| + | |
| + | /** |
| + | * When the button is associated to a empty object |
| + | * fn and title attributs are defined from the button key value |
| + | * |
| + | * For example |
| + | * foo: {} |
| + | * is equivalent to : |
| + | * foo: { |
| + | * fn: 'foo', |
| + | * title: this.lang.foo |
| + | * } |
| + | */ |
| + | var h = t.lang.header, // Header translation |
| + | isBlinkFunction = function () { |
| + | return (window.chrome || (window.Intl && Intl.v8BreakIterator)) && 'CSS' in window; |
| + | }; |
| + | t.btnsDef = { |
| + | viewHTML: { |
| + | fn: 'toggle' |
| + | }, |
| + | |
| + | undo: { |
| + | isSupported: isBlinkFunction, |
| + | key: 'Z' |
| + | }, |
| + | redo: { |
| + | isSupported: isBlinkFunction, |
| + | key: 'Y' |
| + | }, |
| + | |
| + | p: { |
| + | fn: 'formatBlock' |
| + | }, |
| + | blockquote: { |
| + | fn: 'formatBlock' |
| + | }, |
| + | h1: { |
| + | fn: 'formatBlock', |
| + | title: h + ' 1' |
| + | }, |
| + | h2: { |
| + | fn: 'formatBlock', |
| + | title: h + ' 2' |
| + | }, |
| + | h3: { |
| + | fn: 'formatBlock', |
| + | title: h + ' 3' |
| + | }, |
| + | h4: { |
| + | fn: 'formatBlock', |
| + | title: h + ' 4' |
| + | }, |
| + | subscript: { |
| + | tag: 'sub' |
| + | }, |
| + | superscript: { |
| + | tag: 'sup' |
| + | }, |
| + | |
| + | bold: { |
| + | key: 'B', |
| + | tag: 'b' |
| + | }, |
| + | italic: { |
| + | key: 'I', |
| + | tag: 'i' |
| + | }, |
| + | underline: { |
| + | tag: 'u' |
| + | }, |
| + | strikethrough: { |
| + | tag: 'strike' |
| + | }, |
| + | |
| + | strong: { |
| + | fn: 'bold', |
| + | key: 'B' |
| + | }, |
| + | em: { |
| + | fn: 'italic', |
| + | key: 'I' |
| + | }, |
| + | del: { |
| + | fn: 'strikethrough' |
| + | }, |
| + | |
| + | createLink: { |
| + | key: 'K', |
| + | tag: 'a' |
| + | }, |
| + | unlink: {}, |
| + | |
| + | insertImage: {}, |
| + | |
| + | justifyLeft: { |
| + | tag: 'left', |
| + | forceCss: true |
| + | }, |
| + | justifyCenter: { |
| + | tag: 'center', |
| + | forceCss: true |
| + | }, |
| + | justifyRight: { |
| + | tag: 'right', |
| + | forceCss: true |
| + | }, |
| + | justifyFull: { |
| + | tag: 'justify', |
| + | forceCss: true |
| + | }, |
| + | |
| + | unorderedList: { |
| + | fn: 'insertUnorderedList', |
| + | tag: 'ul' |
| + | }, |
| + | orderedList: { |
| + | fn: 'insertOrderedList', |
| + | tag: 'ol' |
| + | }, |
| + | |
| + | horizontalRule: { |
| + | fn: 'insertHorizontalRule' |
| + | }, |
| + | |
| + | removeformat: {}, |
| + | |
| + | fullscreen: { |
| + | class: 'trumbowyg-not-disable' |
| + | }, |
| + | close: { |
| + | fn: 'destroy', |
| + | class: 'trumbowyg-not-disable' |
| + | }, |
| + | |
| + | // Dropdowns |
| + | formatting: { |
| + | dropdown: ['p', 'blockquote', 'h1', 'h2', 'h3', 'h4'], |
| + | ico: 'p' |
| + | }, |
| + | link: { |
| + | dropdown: ['createLink', 'unlink'] |
| + | } |
| + | }; |
| + | |
| + | // Defaults Options |
| + | t.o = $.extend(true, {}, $trumbowyg.defaultOptions, options); |
| + | if (!t.o.hasOwnProperty('imgDblClickHandler')) { |
| + | t.o.imgDblClickHandler = t.getDefaultImgDblClickHandler(); |
| + | } |
| + | |
| + | t.disabled = t.o.disabled || (editorElem.nodeName === 'TEXTAREA' && editorElem.disabled); |
| + | |
| + | if (options.btns) { |
| + | t.o.btns = options.btns; |
| + | } else if (!t.o.semantic) { |
| + | t.o.btns[3] = ['bold', 'italic', 'underline', 'strikethrough']; |
| + | } |
| + | |
| + | $.each(t.o.btnsDef, function (btnName, btnDef) { |
| + | t.addBtnDef(btnName, btnDef); |
| + | }); |
| + | |
| + | // put this here in the event it would be merged in with options |
| + | t.eventNamespace = 'trumbowyg-event'; |
| + | |
| + | // Keyboard shortcuts are load in this array |
| + | t.keys = []; |
| + | |
| + | // Tag to button dynamically hydrated |
| + | t.tagToButton = {}; |
| + | t.tagHandlers = []; |
| + | |
| + | // Admit multiple paste handlers |
| + | t.pasteHandlers = [].concat(t.o.pasteHandlers); |
| + | |
| + | // Check if browser is IE |
| + | t.isIE = (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') !== -1); |
| + | |
| + | t.init(); |
| + | }; |
| + | |
| + | Trumbowyg.prototype = { |
| + | init: function () { |
| + | var t = this; |
| + | t.height = t.$ta.height(); |
| + | |
| + | t.initPlugins(); |
| + | |
| + | try { |
| + | // Disable image resize, try-catch for old IE |
| + | t.doc.execCommand('enableObjectResizing', false, false); |
| + | t.doc.execCommand('defaultParagraphSeparator', false, 'p'); |
| + | } catch (e) { |
| + | } |
| + | |
| + | t.buildEditor(); |
| + | t.buildBtnPane(); |
| + | |
| + | t.fixedBtnPaneEvents(); |
| + | |
| + | t.buildOverlay(); |
| + | |
| + | setTimeout(function () { |
| + | if (t.disabled) { |
| + | t.setDisabled(true); |
| + | } |
| + | t.$c.trigger('tbwinit'); |
| + | }); |
| + | }, |
| + | |
| + | addBtnDef: function (btnName, btnDef) { |
| + | this.btnsDef[btnName] = btnDef; |
| + | }, |
| + | |
| + | buildEditor: function () { |
| + | var t = this, |
| + | prefix = t.o.prefix, |
| + | html = ''; |
| + | |
| + | t.$box = $('<div/>', { |
| + | class: prefix + 'box ' + prefix + 'editor-visible ' + prefix + t.o.lang + ' trumbowyg' |
| + | }); |
| + | |
| + | // $ta = Textarea |
| + | // $ed = Editor |
| + | t.isTextarea = t.$ta.is('textarea'); |
| + | if (t.isTextarea) { |
| + | html = t.$ta.val(); |
| + | t.$ed = $('<div/>'); |
| + | t.$box |
| + | .insertAfter(t.$ta) |
| + | .append(t.$ed, t.$ta); |
| + | } else { |
| + | t.$ed = t.$ta; |
| + | html = t.$ed.html(); |
| + | |
| + | t.$ta = $('<textarea/>', { |
| + | name: t.$ta.attr('id'), |
| + | height: t.height |
| + | }).val(html); |
| + | |
| + | t.$box |
| + | .insertAfter(t.$ed) |
| + | .append(t.$ta, t.$ed); |
| + | t.syncCode(); |
| + | } |
| + | |
| + | t.$ta |
| + | .addClass(prefix + 'textarea') |
| + | .attr('tabindex', -1) |
| + | ; |
| + | |
| + | t.$ed |
| + | .addClass(prefix + 'editor') |
| + | .attr({ |
| + | contenteditable: true, |
| + | dir: t.lang._dir || 'ltr' |
| + | }) |
| + | .html(html) |
| + | ; |
| + | |
| + | if (t.o.tabindex) { |
| + | t.$ed.attr('tabindex', t.o.tabindex); |
| + | } |
| + | |
| + | if (t.$c.is('[placeholder]')) { |
| + | t.$ed.attr('placeholder', t.$c.attr('placeholder')); |
| + | } |
| + | |
| + | if (t.$c.is('[spellcheck]')) { |
| + | t.$ed.attr('spellcheck', t.$c.attr('spellcheck')); |
| + | } |
| + | |
| + | if (t.o.resetCss) { |
| + | t.$ed.addClass(prefix + 'reset-css'); |
| + | } |
| + | |
| + | if (!t.o.autogrow) { |
| + | t.$ta.add(t.$ed).css({ |
| + | height: t.height |
| + | }); |
| + | } |
| + | |
| + | t.semanticCode(); |
| + | |
| + | if (t.o.autogrowOnEnter) { |
| + | t.$ed.addClass(prefix + 'autogrow-on-enter'); |
| + | } |
| + | |
| + | var ctrl = false, |
| + | composition = false, |
| + | debounceButtonPaneStatus, |
| + | updateEventName = 'keyup'; |
| + | |
| + | t.$ed |
| + | .on('dblclick', 'img', t.o.imgDblClickHandler) |
| + | .on('keydown', function (e) { |
| + | if ((e.ctrlKey || e.metaKey) && !e.altKey) { |
| + | ctrl = true; |
| + | var key = t.keys[String.fromCharCode(e.which).toUpperCase()]; |
| + | |
| + | try { |
| + | t.execCmd(key.fn, key.param); |
| + | return false; |
| + | } catch (c) { |
| + | } |
| + | } |
| + | }) |
| + | .on('compositionstart compositionupdate', function () { |
| + | composition = true; |
| + | }) |
| + | .on(updateEventName + ' compositionend', function (e) { |
| + | if (e.type === 'compositionend') { |
| + | composition = false; |
| + | } else if (composition) { |
| + | return; |
| + | } |
| + | |
| + | var keyCode = e.which; |
| + | |
| + | if (keyCode >= 37 && keyCode <= 40) { |
| + | return; |
| + | } |
| + | |
| + | if ((e.ctrlKey || e.metaKey) && (keyCode === 89 || keyCode === 90)) { |
| + | t.$c.trigger('tbwchange'); |
| + | } else if (!ctrl && keyCode !== 17) { |
| + | var compositionend_ie = t.isIE ? e.type === 'compositionend' : true; |
| + | t.semanticCode(false, compositionend_ie && keyCode === 13); |
| + | t.$c.trigger('tbwchange'); |
| + | } else if (typeof e.which === 'undefined') { |
| + | t.semanticCode(false, false, true); |
| + | } |
| + | |
| + | setTimeout(function () { |
| + | ctrl = false; |
| + | }, 50); |
| + | }) |
| + | .on('mouseup keydown keyup', function (e) { |
| + | if ((!e.ctrlKey && !e.metaKey) || e.altKey) { |
| + | setTimeout(function () { // "hold on" to the ctrl key for 50ms |
| + | ctrl = false; |
| + | }, 50); |
| + | } |
| + | clearTimeout(debounceButtonPaneStatus); |
| + | debounceButtonPaneStatus = setTimeout(function () { |
| + | t.updateButtonPaneStatus(); |
| + | }, 50); |
| + | }) |
| + | .on('focus blur', function (e) { |
| + | t.$c.trigger('tbw' + e.type); |
| + | if (e.type === 'blur') { |
| + | $('.' + prefix + 'active-button', t.$btnPane).removeClass(prefix + 'active-button ' + prefix + 'active'); |
| + | } |
| + | if (t.o.autogrowOnEnter) { |
| + | if (t.autogrowOnEnterDontClose) { |
| + | return; |
| + | } |
| + | if (e.type === 'focus') { |
| + | t.autogrowOnEnterWasFocused = true; |
| + | t.autogrowEditorOnEnter(); |
| + | } |
| + | else if (!t.o.autogrow) { |
| + | t.$ed.css({height: t.$ed.css('min-height')}); |
| + | t.$c.trigger('tbwresize'); |
| + | } |
| + | } |
| + | }) |
| + | .on('cut', function () { |
| + | setTimeout(function () { |
| + | t.semanticCode(false, true); |
| + | t.$c.trigger('tbwchange'); |
| + | }, 0); |
| + | }) |
| + | .on('paste', function (e) { |
| + | if (t.o.removeformatPasted) { |
| + | e.preventDefault(); |
| + | |
| + | if (window.getSelection && window.getSelection().deleteFromDocument) { |
| + | window.getSelection().deleteFromDocument(); |
| + | } |
| + | |
| + | try { |
| + | // IE |
| + | var text = window.clipboardData.getData('Text'); |
| + | |
| + | try { |
| + | // <= IE10 |
| + | t.doc.selection.createRange().pasteHTML(text); |
| + | } catch (c) { |
| + | // IE 11 |
| + | t.doc.getSelection().getRangeAt(0).insertNode(t.doc.createTextNode(text)); |
| + | } |
| + | t.$c.trigger('tbwchange', e); |
| + | } catch (d) { |
| + | // Not IE |
| + | t.execCmd('insertText', (e.originalEvent || e).clipboardData.getData('text/plain')); |
| + | } |
| + | } |
| + | |
| + | // Call pasteHandlers |
| + | $.each(t.pasteHandlers, function (i, pasteHandler) { |
| + | pasteHandler(e); |
| + | }); |
| + | |
| + | setTimeout(function () { |
| + | t.semanticCode(false, true); |
| + | t.$c.trigger('tbwpaste', e); |
| + | }, 0); |
| + | }); |
| + | |
| + | t.$ta |
| + | .on('keyup', function () { |
| + | t.$c.trigger('tbwchange'); |
| + | }) |
| + | .on('paste', function () { |
| + | setTimeout(function () { |
| + | t.$c.trigger('tbwchange'); |
| + | }, 0); |
| + | }); |
| + | |
| + | t.$box.on('keydown', function (e) { |
| + | if (e.which === 27 && $('.' + prefix + 'modal-box', t.$box).length === 1) { |
| + | t.closeModal(); |
| + | return false; |
| + | } |
| + | }); |
| + | }, |
| + | |
| + | //autogrow when entering logic |
| + | autogrowEditorOnEnter: function () { |
| + | var t = this; |
| + | t.$ed.removeClass('autogrow-on-enter'); |
| + | var oldHeight = t.$ed[0].clientHeight; |
| + | t.$ed.height('auto'); |
| + | var totalHeight = t.$ed[0].scrollHeight; |
| + | t.$ed.addClass('autogrow-on-enter'); |
| + | if (oldHeight !== totalHeight) { |
| + | t.$ed.height(oldHeight); |
| + | setTimeout(function () { |
| + | t.$ed.css({height: totalHeight}); |
| + | t.$c.trigger('tbwresize'); |
| + | }, 0); |
| + | } |
| + | }, |
| + | |
| + | |
| + | // Build button pane, use o.btns option |
| + | buildBtnPane: function () { |
| + | var t = this, |
| + | prefix = t.o.prefix; |
| + | |
| + | var $btnPane = t.$btnPane = $('<div/>', { |
| + | class: prefix + 'button-pane' |
| + | }); |
| + | |
| + | $.each(t.o.btns, function (i, btnGrp) { |
| + | if (!$.isArray(btnGrp)) { |
| + | btnGrp = [btnGrp]; |
| + | } |
| + | |
| + | var $btnGroup = $('<div/>', { |
| + | class: prefix + 'button-group ' + ((btnGrp.indexOf('fullscreen') >= 0) ? prefix + 'right' : '') |
| + | }); |
| + | $.each(btnGrp, function (i, btn) { |
| + | try { // Prevent buildBtn error |
| + | if (t.isSupportedBtn(btn)) { // It's a supported button |
| + | $btnGroup.append(t.buildBtn(btn)); |
| + | } |
| + | } catch (c) { |
| + | } |
| + | }); |
| + | |
| + | if ($btnGroup.html().trim().length > 0) { |
| + | $btnPane.append($btnGroup); |
| + | } |
| + | }); |
| + | |
| + | t.$box.prepend($btnPane); |
| + | }, |
| + | |
| + | |
| + | // Build a button and his action |
| + | buildBtn: function (btnName) { // btnName is name of the button |
| + | var t = this, |
| + | prefix = t.o.prefix, |
| + | btn = t.btnsDef[btnName], |
| + | isDropdown = btn.dropdown, |
| + | hasIcon = btn.hasIcon != null ? btn.hasIcon : true, |
| + | textDef = t.lang[btnName] || btnName, |
| + | |
| + | $btn = $('<button/>', { |
| + | type: 'button', |
| + | class: prefix + btnName + '-button ' + (btn.class || '') + (!hasIcon ? ' ' + prefix + 'textual-button' : ''), |
| + | html: t.hasSvg && hasIcon ? |
| + | '<svg><use xlink:href="' + t.svgPath + '#' + prefix + (btn.ico || btnName).replace(/([A-Z]+)/g, '-$1').toLowerCase() + '"/></svg>' : |
| + | t.hideButtonTexts ? '' : (btn.text || btn.title || t.lang[btnName] || btnName), |
| + | title: (btn.title || btn.text || textDef) + ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : ''), |
| + | tabindex: -1, |
| + | mousedown: function () { |
| + | if (!isDropdown || $('.' + btnName + '-' + prefix + 'dropdown', t.$box).is(':hidden')) { |
| + | $('body', t.doc).trigger('mousedown'); |
| + | } |
| + | |
| + | if ((t.$btnPane.hasClass(prefix + 'disable') || t.$box.hasClass(prefix + 'disabled')) && |
| + | !$(this).hasClass(prefix + 'active') && |
| + | !$(this).hasClass(prefix + 'not-disable')) { |
| + | return false; |
| + | } |
| + | |
| + | t.execCmd((isDropdown ? 'dropdown' : false) || btn.fn || btnName, btn.param || btnName, btn.forceCss); |
| + | |
| + | return false; |
| + | } |
| + | }); |
| + | |
| + | if (isDropdown) { |
| + | $btn.addClass(prefix + 'open-dropdown'); |
| + | var dropdownPrefix = prefix + 'dropdown', |
| + | dropdownOptions = { // the dropdown |
| + | class: dropdownPrefix + '-' + btnName + ' ' + dropdownPrefix + ' ' + prefix + 'fixed-top' |
| + | }; |
| + | dropdownOptions['data-' + dropdownPrefix] = btnName; |
| + | var $dropdown = $('<div/>', dropdownOptions); |
| + | $.each(isDropdown, function (i, def) { |
| + | if (t.btnsDef[def] && t.isSupportedBtn(def)) { |
| + | $dropdown.append(t.buildSubBtn(def)); |
| + | } |
| + | }); |
| + | t.$box.append($dropdown.hide()); |
| + | } else if (btn.key) { |
| + | t.keys[btn.key] = { |
| + | fn: btn.fn || btnName, |
| + | param: btn.param || btnName |
| + | }; |
| + | } |
| + | |
| + | if (!isDropdown) { |
| + | t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName; |
| + | } |
| + | |
| + | return $btn; |
| + | }, |
| + | // Build a button for dropdown menu |
| + | // @param n : name of the subbutton |
| + | buildSubBtn: function (btnName) { |
| + | var t = this, |
| + | prefix = t.o.prefix, |
| + | btn = t.btnsDef[btnName], |
| + | hasIcon = btn.hasIcon != null ? btn.hasIcon : true; |
| + | |
| + | if (btn.key) { |
| + | t.keys[btn.key] = { |
| + | fn: btn.fn || btnName, |
| + | param: btn.param || btnName |
| + | }; |
| + | } |
| + | |
| + | t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName; |
| + | |
| + | return $('<button/>', { |
| + | type: 'button', |
| + | class: prefix + btnName + '-dropdown-button' + (btn.ico ? ' ' + prefix + btn.ico + '-button' : ''), |
| + | html: t.hasSvg && hasIcon ? '<svg><use xlink:href="' + t.svgPath + '#' + prefix + (btn.ico || btnName).replace(/([A-Z]+)/g, '-$1').toLowerCase() + '"/></svg>' + (btn.text || btn.title || t.lang[btnName] || btnName) : (btn.text || btn.title || t.lang[btnName] || btnName), |
| + | title: ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : null), |
| + | style: btn.style || null, |
| + | mousedown: function () { |
| + | $('body', t.doc).trigger('mousedown'); |
| + | |
| + | t.execCmd(btn.fn || btnName, btn.param || btnName, btn.forceCss); |
| + | |
| + | return false; |
| + | } |
| + | }); |
| + | }, |
| + | // Check if button is supported |
| + | isSupportedBtn: function (b) { |
| + | try { |
| + | return this.btnsDef[b].isSupported(); |
| + | } catch (c) { |
| + | } |
| + | return true; |
| + | }, |
| + | |
| + | // Build overlay for modal box |
| + | buildOverlay: function () { |
| + | var t = this; |
| + | t.$overlay = $('<div/>', { |
| + | class: t.o.prefix + 'overlay' |
| + | }).appendTo(t.$box); |
| + | return t.$overlay; |
| + | }, |
| + | showOverlay: function () { |
| + | var t = this; |
| + | $(window).trigger('scroll'); |
| + | t.$overlay.fadeIn(200); |
| + | t.$box.addClass(t.o.prefix + 'box-blur'); |
| + | }, |
| + | hideOverlay: function () { |
| + | var t = this; |
| + | t.$overlay.fadeOut(50); |
| + | t.$box.removeClass(t.o.prefix + 'box-blur'); |
| + | }, |
| + | |
| + | // Management of fixed button pane |
| + | fixedBtnPaneEvents: function () { |
| + | var t = this, |
| + | fixedFullWidth = t.o.fixedFullWidth, |
| + | $box = t.$box; |
| + | |
| + | if (!t.o.fixedBtnPane) { |
| + | return; |
| + | } |
| + | |
| + | t.isFixed = false; |
| + | |
| + | $(window) |
| + | .on('scroll.' + t.eventNamespace + ' resize.' + t.eventNamespace, function () { |
| + | if (!$box) { |
| + | return; |
| + | } |
| + | |
| + | t.syncCode(); |
| + | |
| + | var scrollTop = $(window).scrollTop(), |
| + | offset = $box.offset().top + 1, |
| + | bp = t.$btnPane, |
| + | oh = bp.outerHeight() - 2; |
| + | |
| + | if ((scrollTop - offset > 0) && ((scrollTop - offset - t.height) < 0)) { |
| + | if (!t.isFixed) { |
| + | t.isFixed = true; |
| + | bp.css({ |
| + | position: 'fixed', |
| + | top: 0, |
| + | left: fixedFullWidth ? '0' : 'auto', |
| + | zIndex: 7 |
| + | }); |
| + | $([t.$ta, t.$ed]).css({marginTop: bp.height()}); |
| + | } |
| + | bp.css({ |
| + | width: fixedFullWidth ? '100%' : (($box.width() - 1) + 'px') |
| + | }); |
| + | |
| + | $('.' + t.o.prefix + 'fixed-top', $box).css({ |
| + | position: fixedFullWidth ? 'fixed' : 'absolute', |
| + | top: fixedFullWidth ? oh : oh + (scrollTop - offset) + 'px', |
| + | zIndex: 15 |
| + | }); |
| + | } else if (t.isFixed) { |
| + | t.isFixed = false; |
| + | bp.removeAttr('style'); |
| + | $([t.$ta, t.$ed]).css({marginTop: 0}); |
| + | $('.' + t.o.prefix + 'fixed-top', $box).css({ |
| + | position: 'absolute', |
| + | top: oh |
| + | }); |
| + | } |
| + | }); |
| + | }, |
| + | |
| + | // Disable editor |
| + | setDisabled: function (disable) { |
| + | var t = this, |
| + | prefix = t.o.prefix; |
| + | |
| + | t.disabled = disable; |
| + | |
| + | if (disable) { |
| + | t.$ta.attr('disabled', true); |
| + | } else { |
| + | t.$ta.removeAttr('disabled'); |
| + | } |
| + | t.$box.toggleClass(prefix + 'disabled', disable); |
| + | t.$ed.attr('contenteditable', !disable); |
| + | }, |
| + | |
| + | // Destroy the editor |
| + | destroy: function () { |
| + | var t = this, |
| + | prefix = t.o.prefix; |
| + | |
| + | if (t.isTextarea) { |
| + | t.$box.after( |
| + | t.$ta |
| + | .css({height: ''}) |
| + | .val(t.html()) |
| + | .removeClass(prefix + 'textarea') |
| + | .show() |
| + | ); |
| + | } else { |
| + | t.$box.after( |
| + | t.$ed |
| + | .css({height: ''}) |
| + | .removeClass(prefix + 'editor') |
| + | .removeAttr('contenteditable') |
| + | .removeAttr('dir') |
| + | .html(t.html()) |
| + | .show() |
| + | ); |
| + | } |
| + | |
| + | t.$ed.off('dblclick', 'img'); |
| + | |
| + | t.destroyPlugins(); |
| + | |
| + | t.$box.remove(); |
| + | t.$c.removeData('trumbowyg'); |
| + | $('body').removeClass(prefix + 'body-fullscreen'); |
| + | t.$c.trigger('tbwclose'); |
| + | $(window).off('scroll.' + t.eventNamespace + ' resize.' + t.eventNamespace); |
| + | }, |
| + | |
| + | |
| + | // Empty the editor |
| + | empty: function () { |
| + | this.$ta.val(''); |
| + | this.syncCode(true); |
| + | }, |
| + | |
| + | |
| + | // Function call when click on viewHTML button |
| + | toggle: function () { |
| + | var t = this, |
| + | prefix = t.o.prefix; |
| + | |
| + | if (t.o.autogrowOnEnter) { |
| + | t.autogrowOnEnterDontClose = !t.$box.hasClass(prefix + 'editor-hidden'); |
| + | } |
| + | |
| + | t.semanticCode(false, true); |
| + | |
| + | setTimeout(function () { |
| + | t.doc.activeElement.blur(); |
| + | t.$box.toggleClass(prefix + 'editor-hidden ' + prefix + 'editor-visible'); |
| + | t.$btnPane.toggleClass(prefix + 'disable'); |
| + | $('.' + prefix + 'viewHTML-button', t.$btnPane).toggleClass(prefix + 'active'); |
| + | if (t.$box.hasClass(prefix + 'editor-visible')) { |
| + | t.$ta.attr('tabindex', -1); |
| + | } else { |
| + | t.$ta.removeAttr('tabindex'); |
| + | } |
| + | |
| + | if (t.o.autogrowOnEnter && !t.autogrowOnEnterDontClose) { |
| + | t.autogrowEditorOnEnter(); |
| + | } |
| + | }, 0); |
| + | }, |
| + | |
| + | // Open dropdown when click on a button which open that |
| + | dropdown: function (name) { |
| + | var t = this, |
| + | d = t.doc, |
| + | prefix = t.o.prefix, |
| + | $dropdown = $('[data-' + prefix + 'dropdown=' + name + ']', t.$box), |
| + | $btn = $('.' + prefix + name + '-button', t.$btnPane), |
| + | show = $dropdown.is(':hidden'); |
| + | |
| + | $('body', d).trigger('mousedown'); |
| + | |
| + | if (show) { |
| + | var o = $btn.offset().left; |
| + | $btn.addClass(prefix + 'active'); |
| + | |
| + | $dropdown.css({ |
| + | position: 'absolute', |
| + | top: $btn.offset().top - t.$btnPane.offset().top + $btn.outerHeight(), |
| + | left: (t.o.fixedFullWidth && t.isFixed) ? o + 'px' : (o - t.$btnPane.offset().left) + 'px' |
| + | }).show(); |
| + | |
| + | $(window).trigger('scroll'); |
| + | |
| + | $('body', d).on('mousedown.' + t.eventNamespace, function (e) { |
| + | if (!$dropdown.is(e.target)) { |
| + | $('.' + prefix + 'dropdown', t.$box).hide(); |
| + | $('.' + prefix + 'active', t.$btnPane).removeClass(prefix + 'active'); |
| + | $('body', d).off('mousedown.' + t.eventNamespace); |
| + | } |
| + | }); |
| + | } |
| + | }, |
| + | |
| + | |
| + | // HTML Code management |
| + | html: function (html) { |
| + | var t = this; |
| + | if (html != null) { |
| + | t.$ta.val(html); |
| + | t.syncCode(true); |
| + | return t; |
| + | } |
| + | return t.$ta.val(); |
| + | }, |
| + | syncTextarea: function () { |
| + | var t = this; |
| + | t.$ta.val(t.$ed.text().trim().length > 0 || t.$ed.find('hr,img,embed,iframe,input').length > 0 ? t.$ed.html() : ''); |
| + | }, |
| + | syncCode: function (force) { |
| + | var t = this; |
| + | if (!force && t.$ed.is(':visible')) { |
| + | t.syncTextarea(); |
| + | } else { |
| + | // wrap the content in a div it's easier to get the innerhtml |
| + | var html = $('<div>').html(t.$ta.val()); |
| + | //scrub the html before loading into the doc |
| + | var safe = $('<div>').append(html); |
| + | $(t.o.tagsToRemove.join(','), safe).remove(); |
| + | t.$ed.html(safe.contents().html()); |
| + | } |
| + | |
| + | if (t.o.autogrow) { |
| + | t.height = t.$ed.height(); |
| + | if (t.height !== t.$ta.css('height')) { |
| + | t.$ta.css({height: t.height}); |
| + | t.$c.trigger('tbwresize'); |
| + | } |
| + | } |
| + | if (t.o.autogrowOnEnter) { |
| + | // t.autogrowEditorOnEnter(); |
| + | t.$ed.height('auto'); |
| + | var totalheight = t.autogrowOnEnterWasFocused ? t.$ed[0].scrollHeight : t.$ed.css('min-height'); |
| + | if (totalheight !== t.$ta.css('height')) { |
| + | t.$ed.css({height: totalheight}); |
| + | t.$c.trigger('tbwresize'); |
| + | } |
| + | } |
| + | }, |
| + | |
| + | // Analyse and update to semantic code |
| + | // @param force : force to sync code from textarea |
| + | // @param full : wrap text nodes in <p> |
| + | // @param keepRange : leave selection range as it is |
| + | semanticCode: function (force, full, keepRange) { |
| + | var t = this; |
| + | t.saveRange(); |
| + | t.syncCode(force); |
| + | |
| + | if (t.o.semantic) { |
| + | t.semanticTag('b', 'strong'); |
| + | t.semanticTag('i', 'em'); |
| + | t.semanticTag('s', 'del'); |
| + | t.semanticTag('strike', 'del'); |
| + | |
| + | if (full) { |
| + | var inlineElementsSelector = t.o.inlineElementsSelector, |
| + | blockElementsSelector = ':not(' + inlineElementsSelector + ')'; |
| + | |
| + | // Wrap text nodes in span for easier processing |
| + | t.$ed.contents().filter(function () { |
| + | return this.nodeType === 3 && this.nodeValue.trim().length > 0; |
| + | }).wrap('<span data-tbw/>'); |
| + | |
| + | // Wrap groups of inline elements in paragraphs (recursive) |
| + | var wrapInlinesInParagraphsFrom = function ($from) { |
| + | if ($from.length !== 0) { |
| + | var $finalParagraph = $from.nextUntil(blockElementsSelector).addBack().wrapAll('<p/>').parent(), |
| + | $nextElement = $finalParagraph.nextAll(inlineElementsSelector).first(); |
| + | $finalParagraph.next('br').remove(); |
| + | wrapInlinesInParagraphsFrom($nextElement); |
| + | } |
| + | }; |
| + | wrapInlinesInParagraphsFrom(t.$ed.children(inlineElementsSelector).first()); |
| + | |
| + | t.semanticTag('div', 'p', true); |
| + | |
| + | // Unwrap paragraphs content, containing nothing usefull |
| + | t.$ed.find('p').filter(function () { |
| + | // Don't remove currently being edited element |
| + | if (t.range && this === t.range.startContainer) { |
| + | return false; |
| + | } |
| + | return $(this).text().trim().length === 0 && $(this).children().not('br,span').length === 0; |
| + | }).contents().unwrap(); |
| + | |
| + | // Get rid of temporial span's |
| + | $('[data-tbw]', t.$ed).contents().unwrap(); |
| + | |
| + | // Remove empty <p> |
| + | t.$ed.find('p:empty').remove(); |
| + | } |
| + | |
| + | if (!keepRange) { |
| + | t.restoreRange(); |
| + | } |
| + | |
| + | t.syncTextarea(); |
| + | } |
| + | }, |
| + | |
| + | semanticTag: function (oldTag, newTag, copyAttributes) { |
| + | $(oldTag, this.$ed).each(function () { |
| + | var $oldTag = $(this); |
| + | $oldTag.wrap('<' + newTag + '/>'); |
| + | if (copyAttributes) { |
| + | $.each($oldTag.prop('attributes'), function () { |
| + | $oldTag.parent().attr(this.name, this.value); |
| + | }); |
| + | } |
| + | $oldTag.contents().unwrap(); |
| + | }); |
| + | }, |
| + | |
| + | // Function call when user click on "Insert Link" |
| + | createLink: function () { |
| + | var t = this, |
| + | documentSelection = t.doc.getSelection(), |
| + | node = documentSelection.focusNode, |
| + | url, |
| + | title, |
| + | target; |
| + | |
| + | while (['A', 'DIV'].indexOf(node.nodeName) < 0) { |
| + | node = node.parentNode; |
| + | } |
| + | |
| + | if (node && node.nodeName === 'A') { |
| + | var $a = $(node); |
| + | url = $a.attr('href'); |
| + | title = $a.attr('title'); |
| + | target = $a.attr('target'); |
| + | var range = t.doc.createRange(); |
| + | range.selectNode(node); |
| + | documentSelection.removeAllRanges(); |
| + | documentSelection.addRange(range); |
| + | } |
| + | |
| + | t.saveRange(); |
| + | |
| + | t.openModalInsert(t.lang.createLink, { |
| + | url: { |
| + | label: 'URL', |
| + | required: true, |
| + | value: url |
| + | }, |
| + | title: { |
| + | label: t.lang.title, |
| + | value: title |
| + | }, |
| + | text: { |
| + | label: t.lang.text, |
| + | value: new XMLSerializer().serializeToString(documentSelection.getRangeAt(0).cloneContents()) |
| + | }, |
| + | target: { |
| + | label: t.lang.target, |
| + | value: target |
| + | } |
| + | }, function (v) { // v is value |
| + | var link = $(['<a href="', v.url, '">', v.text, '</a>'].join('')); |
| + | if (v.title.length > 0) { |
| + | link.attr('title', v.title); |
| + | } |
| + | if (v.target.length > 0) { |
| + | link.attr('target', v.target); |
| + | } |
| + | t.range.deleteContents(); |
| + | t.range.insertNode(link[0]); |
| + | t.syncCode(); |
| + | t.$c.trigger('tbwchange'); |
| + | return true; |
| + | }); |
| + | }, |
| + | unlink: function () { |
| + | var t = this, |
| + | documentSelection = t.doc.getSelection(), |
| + | node = documentSelection.focusNode; |
| + | |
| + | if (documentSelection.isCollapsed) { |
| + | while (['A', 'DIV'].indexOf(node.nodeName) < 0) { |
| + | node = node.parentNode; |
| + | } |
| + | |
| + | if (node && node.nodeName === 'A') { |
| + | var range = t.doc.createRange(); |
| + | range.selectNode(node); |
| + | documentSelection.removeAllRanges(); |
| + | documentSelection.addRange(range); |
| + | } |
| + | } |
| + | t.execCmd('unlink', undefined, undefined, true); |
| + | }, |
| + | insertImage: function () { |
| + | var t = this; |
| + | t.saveRange(); |
| + | |
| + | var options = { |
| + | url: { |
| + | label: 'URL', |
| + | required: true |
| + | }, |
| + | alt: { |
| + | label: t.lang.description, |
| + | value: t.getRangeText() |
| + | } |
| + | }; |
| + | |
| + | if (t.o.imageWidthModalEdit) { |
| + | options.width = {}; |
| + | } |
| + | |
| + | t.openModalInsert(t.lang.insertImage, options, function (v) { // v are values |
| + | t.execCmd('insertImage', v.url); |
| + | var $img = $('img[src="' + v.url + '"]:not([alt])', t.$box); |
| + | $img.attr('alt', v.alt); |
| + | |
| + | if (t.o.imageWidthModalEdit) { |
| + | $img.attr({ |
| + | width: v.width |
| + | }); |
| + | } |
| + | |
| + | t.syncCode(); |
| + | t.$c.trigger('tbwchange'); |
| + | |
| + | return true; |
| + | }); |
| + | }, |
| + | fullscreen: function () { |
| + | var t = this, |
| + | prefix = t.o.prefix, |
| + | fullscreenCssClass = prefix + 'fullscreen', |
| + | isFullscreen; |
| + | |
| + | t.$box.toggleClass(fullscreenCssClass); |
| + | isFullscreen = t.$box.hasClass(fullscreenCssClass); |
| + | $('body').toggleClass(prefix + 'body-fullscreen', isFullscreen); |
| + | $(window).trigger('scroll'); |
| + | t.$c.trigger('tbw' + (isFullscreen ? 'open' : 'close') + 'fullscreen'); |
| + | }, |
| + | |
| + | |
| + | /* |
| + | * Call method of trumbowyg if exist |
| + | * else try to call anonymous function |
| + | * and finaly native execCommand |
| + | */ |
| + | execCmd: function (cmd, param, forceCss, skipTrumbowyg) { |
| + | var t = this; |
| + | skipTrumbowyg = !!skipTrumbowyg || ''; |
| + | |
| + | if (cmd !== 'dropdown') { |
| + | t.$ed.focus(); |
| + | } |
| + | |
| + | try { |
| + | t.doc.execCommand('styleWithCSS', false, forceCss || false); |
| + | } catch (c) { |
| + | } |
| + | |
| + | try { |
| + | t[cmd + skipTrumbowyg](param); |
| + | } catch (c) { |
| + | try { |
| + | cmd(param); |
| + | } catch (e2) { |
| + | if (cmd === 'insertHorizontalRule') { |
| + | param = undefined; |
| + | } else if (cmd === 'formatBlock' && t.isIE) { |
| + | param = '<' + param + '>'; |
| + | } |
| + | |
| + | t.doc.execCommand(cmd, false, param); |
| + | |
| + | t.syncCode(); |
| + | t.semanticCode(false, true); |
| + | } |
| + | |
| + | if (cmd !== 'dropdown') { |
| + | t.updateButtonPaneStatus(); |
| + | t.$c.trigger('tbwchange'); |
| + | } |
| + | } |
| + | }, |
| + | |
| + | |
| + | // Open a modal box |
| + | openModal: function (title, content) { |
| + | var t = this, |
| + | prefix = t.o.prefix; |
| + | |
| + | // No open a modal box when exist other modal box |
| + | if ($('.' + prefix + 'modal-box', t.$box).length > 0) { |
| + | return false; |
| + | } |
| + | if (t.o.autogrowOnEnter) { |
| + | t.autogrowOnEnterDontClose = true; |
| + | } |
| + | |
| + | t.saveRange(); |
| + | t.showOverlay(); |
| + | |
| + | // Disable all btnPane btns |
| + | t.$btnPane.addClass(prefix + 'disable'); |
| + | |
| + | // Build out of ModalBox, it's the mask for animations |
| + | var $modal = $('<div/>', { |
| + | class: prefix + 'modal ' + prefix + 'fixed-top' |
| + | }).css({ |
| + | top: t.$btnPane.height() |
| + | }).appendTo(t.$box); |
| + | |
| + | // Click on overlay close modal by cancelling them |
| + | t.$overlay.one('click', function () { |
| + | $modal.trigger(CANCEL_EVENT); |
| + | return false; |
| + | }); |
| + | |
| + | // Build the form |
| + | var $form = $('<form/>', { |
| + | action: '', |
| + | html: content |
| + | }) |
| + | .on('submit', function () { |
| + | $modal.trigger(CONFIRM_EVENT); |
| + | return false; |
| + | }) |
| + | .on('reset', function () { |
| + | $modal.trigger(CANCEL_EVENT); |
| + | return false; |
| + | }) |
| + | .on('submit reset', function () { |
| + | if (t.o.autogrowOnEnter) { |
| + | t.autogrowOnEnterDontClose = false; |
| + | } |
| + | }); |
| + | |
| + | |
| + | // Build ModalBox and animate to show them |
| + | var $box = $('<div/>', { |
| + | class: prefix + 'modal-box', |
| + | html: $form |
| + | }) |
| + | .css({ |
| + | top: '-' + t.$btnPane.outerHeight() + 'px', |
| + | opacity: 0 |
| + | }) |
| + | .appendTo($modal) |
| + | .animate({ |
| + | top: 0, |
| + | opacity: 1 |
| + | }, 100); |
| + | |
| + | |
| + | // Append title |
| + | $('<span/>', { |
| + | text: title, |
| + | class: prefix + 'modal-title' |
| + | }).prependTo($box); |
| + | |
| + | $modal.height($box.outerHeight() + 10); |
| + | |
| + | |
| + | // Focus in modal box |
| + | $('input:first', $box).focus(); |
| + | |
| + | |
| + | // Append Confirm and Cancel buttons |
| + | t.buildModalBtn('submit', $box); |
| + | t.buildModalBtn('reset', $box); |
| + | |
| + | |
| + | $(window).trigger('scroll'); |
| + | |
| + | return $modal; |
| + | }, |
| + | // @param n is name of modal |
| + | buildModalBtn: function (n, $modal) { |
| + | var t = this, |
| + | prefix = t.o.prefix; |
| + | |
| + | return $('<button/>', { |
| + | class: prefix + 'modal-button ' + prefix + 'modal-' + n, |
| + | type: n, |
| + | text: t.lang[n] || n |
| + | }).appendTo($('form', $modal)); |
| + | }, |
| + | // close current modal box |
| + | closeModal: function () { |
| + | var t = this, |
| + | prefix = t.o.prefix; |
| + | |
| + | t.$btnPane.removeClass(prefix + 'disable'); |
| + | t.$overlay.off(); |
| + | |
| + | // Find the modal box |
| + | var $modalBox = $('.' + prefix + 'modal-box', t.$box); |
| + | |
| + | $modalBox.animate({ |
| + | top: '-' + $modalBox.height() |
| + | }, 100, function () { |
| + | $modalBox.parent().remove(); |
| + | t.hideOverlay(); |
| + | }); |
| + | |
| + | t.restoreRange(); |
| + | }, |
| + | // Preformated build and management modal |
| + | openModalInsert: function (title, fields, cmd) { |
| + | var t = this, |
| + | prefix = t.o.prefix, |
| + | lg = t.lang, |
| + | html = ''; |
| + | |
| + | $.each(fields, function (fieldName, field) { |
| + | var l = field.label, |
| + | n = field.name || fieldName, |
| + | a = field.attributes || {}; |
| + | |
| + | var attr = Object.keys(a).map(function (prop) { |
| + | return prop + '="' + a[prop] + '"'; |
| + | }).join(' '); |
| + | |
| + | html += '<label><input type="' + (field.type || 'text') + '" name="' + n + '" value="' + (field.value || '').replace(/"/g, '"') + '"' + attr + '><span class="' + prefix + 'input-infos"><span>' + |
| + | ((!l) ? (lg[fieldName] ? lg[fieldName] : fieldName) : (lg[l] ? lg[l] : l)) + |
| + | '</span></span></label>'; |
| + | }); |
| + | |
| + | return t.openModal(title, html) |
| + | .on(CONFIRM_EVENT, function () { |
| + | var $form = $('form', $(this)), |
| + | valid = true, |
| + | values = {}; |
| + | |
| + | $.each(fields, function (fieldName, field) { |
| + | var $field = $('input[name="' + fieldName + '"]', $form), |
| + | inputType = $field.attr('type'); |
| + | |
| + | if (inputType.toLowerCase() === 'checkbox') { |
| + | values[fieldName] = $field.is(':checked'); |
| + | } else { |
| + | values[fieldName] = $.trim($field.val()); |
| + | } |
| + | // Validate value |
| + | if (field.required && values[fieldName] === '') { |
| + | valid = false; |
| + | t.addErrorOnModalField($field, t.lang.required); |
| + | } else if (field.pattern && !field.pattern.test(values[fieldName])) { |
| + | valid = false; |
| + | t.addErrorOnModalField($field, field.patternError); |
| + | } |
| + | }); |
| + | |
| + | if (valid) { |
| + | t.restoreRange(); |
| + | |
| + | if (cmd(values, fields)) { |
| + | t.syncCode(); |
| + | t.$c.trigger('tbwchange'); |
| + | t.closeModal(); |
| + | $(this).off(CONFIRM_EVENT); |
| + | } |
| + | } |
| + | }) |
| + | .one(CANCEL_EVENT, function () { |
| + | $(this).off(CONFIRM_EVENT); |
| + | t.closeModal(); |
| + | }); |
| + | }, |
| + | addErrorOnModalField: function ($field, err) { |
| + | var prefix = this.o.prefix, |
| + | $label = $field.parent(); |
| + | |
| + | $field |
| + | .on('change keyup', function () { |
| + | $label.removeClass(prefix + 'input-error'); |
| + | }); |
| + | |
| + | $label |
| + | .addClass(prefix + 'input-error') |
| + | .find('input+span') |
| + | .append( |
| + | $('<span/>', { |
| + | class: prefix + 'msg-error', |
| + | text: err |
| + | }) |
| + | ); |
| + | }, |
| + | |
| + | getDefaultImgDblClickHandler: function () { |
| + | var t = this; |
| + | |
| + | return function () { |
| + | var $img = $(this), |
| + | src = $img.attr('src'), |
| + | base64 = '(Base64)'; |
| + | |
| + | if (src.indexOf('data:image') === 0) { |
| + | src = base64; |
| + | } |
| + | |
| + | var options = { |
| + | url: { |
| + | label: 'URL', |
| + | value: src, |
| + | required: true |
| + | }, |
| + | alt: { |
| + | label: t.lang.description, |
| + | value: $img.attr('alt') |
| + | } |
| + | }; |
| + | |
| + | if (t.o.imageWidthModalEdit) { |
| + | options.width = { |
| + | value: $img.attr('width') ? $img.attr('width') : '' |
| + | }; |
| + | } |
| + | |
| + | t.openModalInsert(t.lang.insertImage, options, function (v) { |
| + | if (v.src !== base64) { |
| + | $img.attr({ |
| + | src: v.url |
| + | }); |
| + | } |
| + | $img.attr({ |
| + | alt: v.alt |
| + | }); |
| + | |
| + | if (t.o.imageWidthModalEdit) { |
| + | if (parseInt(v.width) > 0) { |
| + | $img.attr({ |
| + | width: v.width |
| + | }); |
| + | } else { |
| + | $img.removeAttr('width'); |
| + | } |
| + | } |
| + | |
| + | return true; |
| + | }); |
| + | return false; |
| + | }; |
| + | }, |
| + | |
| + | // Range management |
| + | saveRange: function () { |
| + | var t = this, |
| + | documentSelection = t.doc.getSelection(); |
| + | |
| + | t.range = null; |
| + | |
| + | if (documentSelection.rangeCount) { |
| + | var savedRange = t.range = documentSelection.getRangeAt(0), |
| + | range = t.doc.createRange(), |
| + | rangeStart; |
| + | range.selectNodeContents(t.$ed[0]); |
| + | range.setEnd(savedRange.startContainer, savedRange.startOffset); |
| + | rangeStart = (range + '').length; |
| + | t.metaRange = { |
| + | start: rangeStart, |
| + | end: rangeStart + (savedRange + '').length |
| + | }; |
| + | } |
| + | }, |
| + | restoreRange: function () { |
| + | var t = this, |
| + | metaRange = t.metaRange, |
| + | savedRange = t.range, |
| + | documentSelection = t.doc.getSelection(), |
| + | range; |
| + | |
| + | if (!savedRange) { |
| + | return; |
| + | } |
| + | |
| + | if (metaRange && metaRange.start !== metaRange.end) { // Algorithm from http://jsfiddle.net/WeWy7/3/ |
| + | var charIndex = 0, |
| + | nodeStack = [t.$ed[0]], |
| + | node, |
| + | foundStart = false, |
| + | stop = false; |
| + | |
| + | range = t.doc.createRange(); |
| + | |
| + | while (!stop && (node = nodeStack.pop())) { |
| + | if (node.nodeType === 3) { |
| + | var nextCharIndex = charIndex + node.length; |
| + | if (!foundStart && metaRange.start >= charIndex && metaRange.start <= nextCharIndex) { |
| + | range.setStart(node, metaRange.start - charIndex); |
| + | foundStart = true; |
| + | } |
| + | if (foundStart && metaRange.end >= charIndex && metaRange.end <= nextCharIndex) { |
| + | range.setEnd(node, metaRange.end - charIndex); |
| + | stop = true; |
| + | } |
| + | charIndex = nextCharIndex; |
| + | } else { |
| + | var cn = node.childNodes, |
| + | i = cn.length; |
| + | |
| + | while (i > 0) { |
| + | i -= 1; |
| + | nodeStack.push(cn[i]); |
| + | } |
| + | } |
| + | } |
| + | } |
| + | |
| + | documentSelection.removeAllRanges(); |
| + | documentSelection.addRange(range || savedRange); |
| + | }, |
| + | getRangeText: function () { |
| + | return this.range + ''; |
| + | }, |
| + | |
| + | updateButtonPaneStatus: function () { |
| + | var t = this, |
| + | prefix = t.o.prefix, |
| + | tags = t.getTagsRecursive(t.doc.getSelection().focusNode), |
| + | activeClasses = prefix + 'active-button ' + prefix + 'active'; |
| + | |
| + | $('.' + prefix + 'active-button', t.$btnPane).removeClass(activeClasses); |
| + | $.each(tags, function (i, tag) { |
| + | var btnName = t.tagToButton[tag.toLowerCase()], |
| + | $btn = $('.' + prefix + btnName + '-button', t.$btnPane); |
| + | |
| + | if ($btn.length > 0) { |
| + | $btn.addClass(activeClasses); |
| + | } else { |
| + | try { |
| + | $btn = $('.' + prefix + 'dropdown .' + prefix + btnName + '-dropdown-button', t.$box); |
| + | var dropdownBtnName = $btn.parent().data('dropdown'); |
| + | $('.' + prefix + dropdownBtnName + '-button', t.$box).addClass(activeClasses); |
| + | } catch (e) { |
| + | } |
| + | } |
| + | }); |
| + | }, |
| + | getTagsRecursive: function (element, tags) { |
| + | var t = this; |
| + | tags = tags || (element && element.tagName ? [element.tagName] : []); |
| + | |
| + | if (element && element.parentNode) { |
| + | element = element.parentNode; |
| + | } else { |
| + | return tags; |
| + | } |
| + | |
| + | var tag = element.tagName; |
| + | if (tag === 'DIV') { |
| + | return tags; |
| + | } |
| + | if (tag === 'P' && element.style.textAlign !== '') { |
| + | tags.push(element.style.textAlign); |
| + | } |
| + | |
| + | $.each(t.tagHandlers, function (i, tagHandler) { |
| + | tags = tags.concat(tagHandler(element, t)); |
| + | }); |
| + | |
| + | tags.push(tag); |
| + | |
| + | return t.getTagsRecursive(element, tags).filter(function(tag) { return tag != null; }); |
| + | }, |
| + | |
| + | // Plugins |
| + | initPlugins: function () { |
| + | var t = this; |
| + | t.loadedPlugins = []; |
| + | $.each($.trumbowyg.plugins, function (name, plugin) { |
| + | if (!plugin.shouldInit || plugin.shouldInit(t)) { |
| + | plugin.init(t); |
| + | if (plugin.tagHandler) { |
| + | t.tagHandlers.push(plugin.tagHandler); |
| + | } |
| + | t.loadedPlugins.push(plugin); |
| + | } |
| + | }); |
| + | }, |
| + | destroyPlugins: function () { |
| + | $.each(this.loadedPlugins, function (i, plugin) { |
| + | if (plugin.destroy) { |
| + | plugin.destroy(); |
| + | } |
| + | }); |
| + | } |
| + | }; |
| + | })(navigator, window, document, jQuery); |
public/stylesheets/app.scss
+3
-1
| @@ | @@ -49,10 +49,12 @@ |
| @include foundation-visibility-classes; | |
| @include foundation-float-classes; | |
| - | @import 'footer'; |
| + | @import "vendor/trumbowyg"; |
| + | @import "footer"; |
| @import "services"; | |
| @import "header"; | |
| + | |
| body, html { | |
| height: 100%; | |
| background: $white; | |
public/stylesheets/vendor/trumbowyg.scss
+794
-0
| @@ | @@ -0,0 +1,794 @@ |
| + | /** |
| + | * Trumbowyg v2.9.4 - A lightweight WYSIWYG editor |
| + | * Default stylesheet for Trumbowyg editor |
| + | * ------------------------ |
| + | * @link http://alex-d.github.io/Trumbowyg |
| + | * @license MIT |
| + | * @author Alexandre Demode (Alex-D) |
| + | * Twitter : @AlexandreDemode |
| + | * Website : alex-d.fr |
| + | */ |
| + | |
| + | $light-color: #ecf0f1 !default; |
| + | $dark-color: #222 !default; |
| + | |
| + | $modal-submit-color: #2ecc71 !default; |
| + | $modal-reset-color: #EEE !default; |
| + | |
| + | $transition-duration: 150ms !default; |
| + | $slow-transition-duration: 300ms !default; |
| + | |
| + | #trumbowyg-icons { |
| + | overflow: hidden; |
| + | visibility: hidden; |
| + | height: 0; |
| + | width: 0; |
| + | |
| + | svg { |
| + | height: 0; |
| + | width: 0; |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-box { |
| + | *, |
| + | *::before, |
| + | *::after { |
| + | box-sizing: border-box; |
| + | } |
| + | |
| + | svg { |
| + | width: 17px; |
| + | height: 100%; |
| + | fill: $dark-color; |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-box, |
| + | .trumbowyg-editor { |
| + | display: block; |
| + | position: relative; |
| + | border: 1px solid #DDD; |
| + | width: 100%; |
| + | min-height: 300px; |
| + | margin: 17px auto; |
| + | } |
| + | |
| + | .trumbowyg-box .trumbowyg-editor { |
| + | margin: 0 auto; |
| + | } |
| + | |
| + | .trumbowyg-box.trumbowyg-fullscreen { |
| + | background: #FEFEFE; |
| + | border: none !important; |
| + | } |
| + | |
| + | .trumbowyg-editor, |
| + | .trumbowyg-textarea { |
| + | position: relative; |
| + | box-sizing: border-box; |
| + | padding: 20px; |
| + | min-height: 300px; |
| + | width: 100%; |
| + | border-style: none; |
| + | resize: none; |
| + | outline: none; |
| + | overflow: auto; |
| + | |
| + | &.trumbowyg-autogrow-on-enter { |
| + | transition: height $slow-transition-duration ease-out; |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-box-blur .trumbowyg-editor { |
| + | *, |
| + | &::before { |
| + | color: transparent !important; |
| + | text-shadow: 0 0 7px #333; |
| + | |
| + | @media screen and (min-width: 0 \0) { |
| + | color: rgba(200, 200, 200, 0.6) !important; |
| + | } |
| + | @supports (-ms-accelerator:true) { |
| + | color: rgba(200, 200, 200, 0.6) !important; |
| + | } |
| + | } |
| + | img, |
| + | hr { |
| + | opacity: 0.2; |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-textarea { |
| + | position: relative; |
| + | display: block; |
| + | overflow: auto; |
| + | border: none; |
| + | font-size: 14px; |
| + | font-family: "Inconsolata", "Consolas", "Courier", "Courier New", sans-serif; |
| + | line-height: 18px; |
| + | } |
| + | |
| + | .trumbowyg-box.trumbowyg-editor-visible { |
| + | .trumbowyg-textarea { |
| + | height: 1px !important; |
| + | width: 25%; |
| + | min-height: 0 !important; |
| + | padding: 0 !important; |
| + | background: none; |
| + | opacity: 0 !important; |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-box.trumbowyg-editor-hidden { |
| + | .trumbowyg-textarea { |
| + | display: block; |
| + | } |
| + | .trumbowyg-editor { |
| + | display: none; |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-box.trumbowyg-disabled { |
| + | .trumbowyg-textarea { |
| + | opacity: 0.8; |
| + | background: none; |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-editor[contenteditable=true]:empty:not(:focus)::before { |
| + | content: attr(placeholder); |
| + | color: #999; |
| + | pointer-events: none; |
| + | } |
| + | |
| + | .trumbowyg-button-pane { |
| + | width: 100%; |
| + | min-height: 36px; |
| + | background: $light-color; |
| + | border-bottom: 1px solid darken($light-color, 7%); |
| + | margin: 0; |
| + | padding: 0 5px; |
| + | position: relative; |
| + | list-style-type: none; |
| + | line-height: 10px; |
| + | backface-visibility: hidden; |
| + | z-index: 11; |
| + | |
| + | &::after { |
| + | content: " "; |
| + | display: block; |
| + | position: absolute; |
| + | top: 36px; |
| + | left: 0; |
| + | right: 0; |
| + | width: 100%; |
| + | height: 1px; |
| + | background: darken($light-color, 7%); |
| + | } |
| + | |
| + | .trumbowyg-button-group { |
| + | display: inline-block; |
| + | |
| + | .trumbowyg-fullscreen-button svg { |
| + | color: transparent; |
| + | } |
| + | |
| + | & + .trumbowyg-button-group::before { |
| + | content: " "; |
| + | display: inline-block; |
| + | width: 1px; |
| + | background: darken($light-color, 7%); |
| + | margin: 0 5px; |
| + | height: 35px; |
| + | vertical-align: top; |
| + | } |
| + | } |
| + | |
| + | button { |
| + | display: inline-block; |
| + | position: relative; |
| + | width: 35px; |
| + | height: 35px; |
| + | padding: 1px 6px !important; |
| + | margin-bottom: 1px; |
| + | overflow: hidden; |
| + | border: none; |
| + | cursor: pointer; |
| + | background: none; |
| + | vertical-align: middle; |
| + | transition: background-color $transition-duration, opacity $transition-duration; |
| + | |
| + | &.trumbowyg-textual-button { |
| + | width: auto; |
| + | line-height: 35px; |
| + | user-select: none; |
| + | } |
| + | } |
| + | |
| + | &.trumbowyg-disable button:not(.trumbowyg-not-disable):not(.trumbowyg-active), |
| + | .trumbowyg-disabled & button:not(.trumbowyg-not-disable):not(.trumbowyg-viewHTML-button) { |
| + | opacity: 0.2; |
| + | cursor: default; |
| + | } |
| + | &.trumbowyg-disable, |
| + | .trumbowyg-disabled & { |
| + | .trumbowyg-button-group::before { |
| + | background: darken($light-color, 3%); |
| + | } |
| + | } |
| + | |
| + | button:not(.trumbowyg-disable):hover, |
| + | button:not(.trumbowyg-disable):focus, |
| + | button.trumbowyg-active { |
| + | background-color: #FFF; |
| + | outline: none; |
| + | } |
| + | |
| + | .trumbowyg-open-dropdown { |
| + | &::after { |
| + | display: block; |
| + | content: " "; |
| + | position: absolute; |
| + | top: 25px; |
| + | right: 3px; |
| + | height: 0; |
| + | width: 0; |
| + | border: 3px solid transparent; |
| + | border-top-color: #555; |
| + | } |
| + | |
| + | &.trumbowyg-textual-button { |
| + | padding-left: 10px !important; |
| + | padding-right: 18px !important; |
| + | |
| + | &::after { |
| + | top: 17px; |
| + | right: 7px; |
| + | } |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-right { |
| + | float: right; |
| + | |
| + | &::before { |
| + | display: none !important; |
| + | } |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-dropdown { |
| + | width: 200px; |
| + | border: 1px solid $light-color; |
| + | padding: 5px 0; |
| + | border-top: none; |
| + | background: #FFF; |
| + | margin-left: -1px; |
| + | box-shadow: rgba(0, 0, 0, .1) 0 2px 3px; |
| + | z-index: 12; |
| + | |
| + | button { |
| + | display: block; |
| + | width: 100%; |
| + | height: 35px; |
| + | line-height: 35px; |
| + | text-decoration: none; |
| + | background: #FFF; |
| + | padding: 0 10px; |
| + | color: #333 !important; |
| + | border: none; |
| + | cursor: pointer; |
| + | text-align: left; |
| + | font-size: 15px; |
| + | transition: all $transition-duration; |
| + | |
| + | &:hover, |
| + | &:focus { |
| + | background: $light-color; |
| + | } |
| + | |
| + | svg { |
| + | float: left; |
| + | margin-right: 14px; |
| + | } |
| + | } |
| + | } |
| + | |
| + | /* Modal box */ |
| + | .trumbowyg-modal { |
| + | position: absolute; |
| + | top: 0; |
| + | left: 50%; |
| + | transform: translateX(-50%); |
| + | max-width: 520px; |
| + | width: 100%; |
| + | height: 350px; |
| + | z-index: 12; |
| + | overflow: hidden; |
| + | backface-visibility: hidden; |
| + | } |
| + | |
| + | .trumbowyg-modal-box { |
| + | position: absolute; |
| + | top: 0; |
| + | left: 50%; |
| + | transform: translateX(-50%); |
| + | max-width: 500px; |
| + | width: calc(100% - 20px); |
| + | padding-bottom: 45px; |
| + | z-index: 1; |
| + | background-color: #FFF; |
| + | text-align: center; |
| + | font-size: 14px; |
| + | box-shadow: rgba(0, 0, 0, .2) 0 2px 3px; |
| + | backface-visibility: hidden; |
| + | |
| + | .trumbowyg-modal-title { |
| + | font-size: 24px; |
| + | font-weight: bold; |
| + | margin: 0 0 20px; |
| + | padding: 15px 0 13px; |
| + | display: block; |
| + | border-bottom: 1px solid #EEE; |
| + | color: #333; |
| + | background: lighten($light-color, 5%); |
| + | } |
| + | |
| + | .trumbowyg-progress { |
| + | width: 100%; |
| + | height: 3px; |
| + | position: absolute; |
| + | top: 58px; |
| + | |
| + | .trumbowyg-progress-bar { |
| + | background: #2BC06A; |
| + | width: 0; |
| + | height: 100%; |
| + | transition: width $transition-duration linear; |
| + | } |
| + | } |
| + | |
| + | label { |
| + | display: block; |
| + | position: relative; |
| + | margin: 15px 12px; |
| + | height: 29px; |
| + | line-height: 29px; |
| + | overflow: hidden; |
| + | |
| + | .trumbowyg-input-infos { |
| + | display: block; |
| + | text-align: left; |
| + | height: 25px; |
| + | line-height: 25px; |
| + | transition: all 150ms; |
| + | |
| + | span { |
| + | display: block; |
| + | color: darken($light-color, 45%); |
| + | background-color: lighten($light-color, 5%); |
| + | border: 1px solid #DEDEDE; |
| + | padding: 0 7px; |
| + | width: 150px; |
| + | } |
| + | span.trumbowyg-msg-error { |
| + | color: #e74c3c; |
| + | } |
| + | } |
| + | |
| + | &.trumbowyg-input-error { |
| + | input, |
| + | textarea { |
| + | border: 1px solid #e74c3c; |
| + | } |
| + | |
| + | .trumbowyg-input-infos { |
| + | margin-top: -27px; |
| + | } |
| + | } |
| + | |
| + | input { |
| + | position: absolute; |
| + | top: 0; |
| + | right: 0; |
| + | height: 27px; |
| + | line-height: 27px; |
| + | border: 1px solid #DEDEDE; |
| + | background: #fff; |
| + | font-size: 14px; |
| + | max-width: 330px; |
| + | width: 70%; |
| + | padding: 0 7px; |
| + | transition: all $transition-duration; |
| + | |
| + | &:hover, |
| + | &:focus { |
| + | outline: none; |
| + | border: 1px solid #95a5a6; |
| + | } |
| + | &:focus { |
| + | background: lighten($light-color, 5%); |
| + | } |
| + | } |
| + | } |
| + | |
| + | .error { |
| + | margin-top: 25px; |
| + | display: block; |
| + | color: red; |
| + | } |
| + | |
| + | .trumbowyg-modal-button { |
| + | position: absolute; |
| + | bottom: 10px; |
| + | right: 0; |
| + | text-decoration: none; |
| + | color: #FFF; |
| + | display: block; |
| + | width: 100px; |
| + | height: 35px; |
| + | line-height: 33px; |
| + | margin: 0 10px; |
| + | background-color: #333; |
| + | border: none; |
| + | cursor: pointer; |
| + | font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif; |
| + | font-size: 16px; |
| + | transition: all $transition-duration; |
| + | |
| + | &.trumbowyg-modal-submit { |
| + | right: 110px; |
| + | background: darken($modal-submit-color, 3%); |
| + | |
| + | &:hover, |
| + | &:focus { |
| + | background: lighten($modal-submit-color, 5%); |
| + | outline: none; |
| + | } |
| + | &:active { |
| + | background: darken($modal-submit-color, 10%); |
| + | } |
| + | } |
| + | |
| + | &.trumbowyg-modal-reset { |
| + | color: #555; |
| + | background: darken($modal-reset-color, 3%); |
| + | |
| + | &:hover, |
| + | &:focus { |
| + | background: lighten($modal-reset-color, 5%); |
| + | outline: none; |
| + | } |
| + | &:active { |
| + | background: darken($modal-reset-color, 10%); |
| + | } |
| + | } |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-overlay { |
| + | position: absolute; |
| + | background-color: rgba(255, 255, 255, 0.5); |
| + | height: 100%; |
| + | width: 100%; |
| + | left: 0; |
| + | display: none; |
| + | top: 0; |
| + | z-index: 10; |
| + | } |
| + | |
| + | /** |
| + | * Fullscreen |
| + | */ |
| + | body.trumbowyg-body-fullscreen { |
| + | overflow: hidden; |
| + | } |
| + | |
| + | .trumbowyg-fullscreen { |
| + | position: fixed; |
| + | top: 0; |
| + | left: 0; |
| + | width: 100%; |
| + | height: 100%; |
| + | margin: 0; |
| + | padding: 0; |
| + | z-index: 99999; |
| + | |
| + | &.trumbowyg-box, |
| + | .trumbowyg-editor { |
| + | border: none; |
| + | } |
| + | .trumbowyg-editor, |
| + | .trumbowyg-textarea { |
| + | height: calc(100% - 37px) !important; |
| + | overflow: auto; |
| + | } |
| + | .trumbowyg-overlay { |
| + | height: 100% !important; |
| + | } |
| + | .trumbowyg-button-group .trumbowyg-fullscreen-button svg { |
| + | color: $dark-color; |
| + | fill: transparent; |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-editor { |
| + | object, |
| + | embed, |
| + | video, |
| + | img { |
| + | max-width: 100%; |
| + | } |
| + | video, |
| + | img { |
| + | height: auto; |
| + | } |
| + | img { |
| + | cursor: move; |
| + | } |
| + | |
| + | /* |
| + | * lset for resetCss option |
| + | */ |
| + | &.trumbowyg-reset-css { |
| + | background: #FEFEFE !important; |
| + | font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important; |
| + | font-size: 14px !important; |
| + | line-height: 1.45em !important; |
| + | color: #333; |
| + | |
| + | a { |
| + | color: #15c !important; |
| + | text-decoration: underline !important; |
| + | } |
| + | |
| + | div, |
| + | p, |
| + | ul, |
| + | ol, |
| + | blockquote { |
| + | box-shadow: none !important; |
| + | background: none !important; |
| + | margin: 0 !important; |
| + | margin-bottom: 15px !important; |
| + | line-height: 1.4em !important; |
| + | font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important; |
| + | font-size: 14px !important; |
| + | border: none; |
| + | } |
| + | iframe, |
| + | object, |
| + | hr { |
| + | margin-bottom: 15px !important; |
| + | } |
| + | blockquote { |
| + | margin-left: 32px !important; |
| + | font-style: italic !important; |
| + | color: #555; |
| + | } |
| + | ul, |
| + | ol { |
| + | padding-left: 20px !important; |
| + | } |
| + | ul ul, |
| + | ol ol, |
| + | ul ol, |
| + | ol ul { |
| + | border: none; |
| + | margin: 2px !important; |
| + | padding: 0 !important; |
| + | padding-left: 24px !important; |
| + | } |
| + | hr { |
| + | display: block; |
| + | height: 1px; |
| + | border: none; |
| + | border-top: 1px solid #CCC; |
| + | } |
| + | |
| + | h1, |
| + | h2, |
| + | h3, |
| + | h4 { |
| + | color: #111; |
| + | background: none; |
| + | margin: 0 !important; |
| + | padding: 0 !important; |
| + | font-weight: bold; |
| + | } |
| + | |
| + | h1 { |
| + | font-size: 32px !important; |
| + | line-height: 38px !important; |
| + | margin-bottom: 20px !important; |
| + | } |
| + | h2 { |
| + | font-size: 26px !important; |
| + | line-height: 34px !important; |
| + | margin-bottom: 15px !important; |
| + | } |
| + | h3 { |
| + | font-size: 22px !important; |
| + | line-height: 28px !important; |
| + | margin-bottom: 7px !important; |
| + | } |
| + | h4 { |
| + | font-size: 16px !important; |
| + | line-height: 22px !important; |
| + | margin-bottom: 7px !important; |
| + | } |
| + | } |
| + | } |
| + | |
| + | /* |
| + | * Dark theme |
| + | */ |
| + | .trumbowyg-dark { |
| + | .trumbowyg-textarea { |
| + | background: #111; |
| + | color: #ddd; |
| + | } |
| + | .trumbowyg-box { |
| + | border: 1px solid lighten($dark-color, 7%); |
| + | |
| + | &.trumbowyg-fullscreen { |
| + | background: #111; |
| + | } |
| + | &.trumbowyg-box-blur .trumbowyg-editor { |
| + | *, |
| + | &::before { |
| + | text-shadow: 0 0 7px #ccc; |
| + | |
| + | @media screen and (min-width: 0 \0 |
| + | ) { |
| + | color: rgba(20, 20, 20, 0.6) !important; |
| + | } |
| + | @supports (-ms-accelerator:true) { |
| + | color: rgba(20, 20, 20, 0.6) !important; |
| + | } |
| + | } |
| + | } |
| + | |
| + | svg { |
| + | fill: $light-color; |
| + | color: $light-color; |
| + | } |
| + | } |
| + | .trumbowyg-button-pane { |
| + | background-color: $dark-color; |
| + | border-bottom-color: lighten($dark-color, 7%); |
| + | |
| + | &::after { |
| + | background: lighten($dark-color, 7%); |
| + | } |
| + | |
| + | .trumbowyg-button-group:not(:empty) { |
| + | &::before { |
| + | background-color: lighten($dark-color, 7%); |
| + | } |
| + | .trumbowyg-fullscreen-button svg { |
| + | color: transparent; |
| + | } |
| + | } |
| + | |
| + | &.trumbowyg-disable { |
| + | .trumbowyg-button-group::before { |
| + | background-color: lighten($dark-color, 3%); |
| + | } |
| + | } |
| + | |
| + | button:not(.trumbowyg-disable):hover, |
| + | button:not(.trumbowyg-disable):focus, |
| + | button.trumbowyg-active { |
| + | background-color: #333; |
| + | } |
| + | |
| + | .trumbowyg-open-dropdown::after { |
| + | border-top-color: #fff; |
| + | } |
| + | } |
| + | .trumbowyg-fullscreen { |
| + | .trumbowyg-button-group .trumbowyg-fullscreen-button svg { |
| + | color: $light-color; |
| + | fill: transparent; |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-dropdown { |
| + | border-color: $dark-color; |
| + | background: #333; |
| + | box-shadow: rgba(0, 0, 0, .3) 0 2px 3px; |
| + | |
| + | button { |
| + | background: #333; |
| + | color: #fff !important; |
| + | |
| + | &:hover, |
| + | &:focus { |
| + | background: $dark-color; |
| + | } |
| + | } |
| + | } |
| + | |
| + | // Modal box |
| + | .trumbowyg-modal-box { |
| + | background-color: $dark-color; |
| + | |
| + | .trumbowyg-modal-title { |
| + | border-bottom: 1px solid #555; |
| + | color: #fff; |
| + | background: lighten($dark-color, 10%); |
| + | } |
| + | |
| + | label { |
| + | display: block; |
| + | position: relative; |
| + | margin: 15px 12px; |
| + | height: 27px; |
| + | line-height: 27px; |
| + | overflow: hidden; |
| + | |
| + | .trumbowyg-input-infos { |
| + | span { |
| + | color: #eee; |
| + | background-color: lighten($dark-color, 5%); |
| + | border-color: $dark-color; |
| + | } |
| + | span.trumbowyg-msg-error { |
| + | color: #e74c3c; |
| + | } |
| + | } |
| + | |
| + | &.trumbowyg-input-error { |
| + | input, |
| + | textarea { |
| + | border-color: #e74c3c; |
| + | } |
| + | } |
| + | |
| + | input { |
| + | border-color: $dark-color; |
| + | color: #eee; |
| + | background: #333; |
| + | |
| + | &:hover, |
| + | &:focus { |
| + | border-color: lighten($dark-color, 25%); |
| + | } |
| + | &:focus { |
| + | background-color: lighten($dark-color, 5%); |
| + | } |
| + | } |
| + | } |
| + | |
| + | .trumbowyg-modal-button { |
| + | &.trumbowyg-modal-submit { |
| + | background: darken($modal-submit-color, 20%); |
| + | |
| + | &:hover, |
| + | &:focus { |
| + | background: darken($modal-submit-color, 10%); |
| + | } |
| + | &:active { |
| + | background: darken($modal-submit-color, 25%); |
| + | } |
| + | } |
| + | &.trumbowyg-modal-reset { |
| + | background: #333; |
| + | color: #ccc; |
| + | |
| + | &:hover, |
| + | &:focus { |
| + | background: #444; |
| + | } |
| + | &:active { |
| + | background: #111; |
| + | } |
| + | } |
| + | } |
| + | } |
| + | .trumbowyg-overlay { |
| + | background-color: rgba(15, 15, 15, 0.6); |
| + | } |
| + | } |